chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:21:23 +08:00
commit b957a53def
5423 changed files with 863745 additions and 0 deletions
@@ -0,0 +1,101 @@
# Semantic Kernel Agents - Getting Started
This project contains a step by step guide to get started with _Semantic Kernel Agents_ in Python.
#### PyPI:
- For the use of Chat Completion agents, the minimum allowed Semantic Kernel pypi version is 1.3.0.
- For the use of OpenAI Assistant agents, the minimum allowed Semantic Kernel pypi version is 1.4.0.
- For the use of Agent Group Chat, the minimum allowed Semantic kernel pypi version is 1.6.0.
- For the use of Streaming OpenAI Assistant agents, the minimum allowed Semantic Kernel pypi version is 1.11.0
- For the use of OpenAI Responses agents, the minimum allowed Semantic Kernel pypi version is 1.27.0.
#### Source
- [Semantic Kernel Agent Framework](../../semantic_kernel/agents/)
## Examples
The getting started with agents examples include:
## Chat Completion
Example|Description
---|---
[step01_chat_completion_agent_simple](../getting_started_with_agents/chat_completion/step01_chat_completion_agent_simple.py)|How to create and use a simple chat completion agent.
[step02_chat_completion_agent_thread_management](../getting_started_with_agents/chat_completion/step02_chat_completion_agent_thread_management.py)|How to create and use a chat completion with a thread.
[step03_chat_completion_agent_with_kernel](../getting_started_with_agents/chat_completion/step03_chat_completion_agent_with_kernel.py)|How to create and use a a chat completion agent with the AI service created on the kernel.
[step04_chat_completion_agent_plugin_simple](../getting_started_with_agents/chat_completion/step04_chat_completion_agent_plugin_simple.py)|How to create a simple chat completion agent and specify plugins via the constructor with a kernel.
[step05_chat_completion_agent_plugin_with_kernel](../getting_started_with_agents/chat_completion/step05_chat_completion_agent_plugin_with_kernel.py)|How to create and use a chat completion agent by registering plugins on the kernel.
[step06_chat_completion_agent_group_chat](../getting_started_with_agents/chat_completion/step06_chat_completion_agent_group_chat.py)|How to create a conversation between agents.
[step07_kernel_function_strategies](../getting_started_with_agents/chat_completion/step07_kernel_function_strategies.py)|How to utilize a `KernelFunction` as a chat strategy.
[step08_chat_completion_agent_json_result](../getting_started_with_agents/chat_completion/step08_chat_completion_agent_json_result.py)|How to have an agent produce JSON.
[step09_chat_completion_agent_logging](../getting_started_with_agents/chat_completion/step09_chat_completion_agent_logging.py)|How to enable logging for agents.
[step10_chat_completion_agent_structured_outputs](../getting_started_with_agents/chat_completion/step10_chat_completion_agent_structured_outputs.py)|How to use have a chat completion agent use structured outputs
[step11_chat_completion_agent_declarative](../getting_started_with_agents/chat_completion/step11_chat_completion_agent_declarative.py)|How to create a chat compltion agent from a declarative spec.
## Azure AI Agent
Example|Description
---|---
[step1_azure_ai_agent](../getting_started_with_agents/azure_ai_agent/step01_azure_ai_agent.py)|How to create an Azure AI Agent and invoke a Semantic Kernel plugin.
[step2_azure_ai_agent_plugin](../getting_started_with_agents/azure_ai_agent/step02_azure_ai_agent_plugin.py)|How to create an Azure AI Agent with plugins.
[step3_azure_ai_agent_group_chat](../getting_started_with_agents/azure_ai_agent/step03_azure_ai_agent_group_chat.py)|How to create an agent group chat with Azure AI Agents.
[step4_azure_ai_agent_code_interpreter](../getting_started_with_agents/azure_ai_agent/step04_azure_ai_agent_code_interpreter.py)|How to use the code-interpreter tool for an Azure AI agent.
[step5_azure_ai_agent_file_search](../getting_started_with_agents/azure_ai_agent/step05_azure_ai_agent_file_search.py)|How to use the file-search tool for an Azure AI agent.
[step6_azure_ai_agent_openapi](../getting_started_with_agents/azure_ai_agent/step06_azure_ai_agent_openapi.py)|How to use the Open API tool for an Azure AI agent.
[step7_azure_ai_agent_retrieval](../getting_started_with_agents/azure_ai_agent/step07_azure_ai_agent_retrieval.py)|How to reference an existing Azure AI Agent.
[step8_azure_ai_agent_declarative](../getting_started_with_agents/azure_ai_agent/step08_azure_ai_agent_declarative.py)|How to create an Azure AI Agent from a declarative spec.
_Note: For details on configuring an Azure AI Agent, please see [here](../getting_started_with_agents/azure_ai_agent/README.md)._
## OpenAI Assistant Agent
Example|Description
---|---
[step1_assistant](../getting_started_with_agents/openai_assistant/step1_assistant.py)|How to create and use an OpenAI Assistant agent.
[step2_assistant_plugins](../getting_started_with_agents/openai_assistant/step2_assistant_plugins.py)| How to create and use an OpenAI Assistant agent with plugins.
[step3_assistant_vision](../getting_started_with_agents/openai_assistant/step3_assistant_vision.py)|How to provide an image as input to an OpenAI Assistant agent.
[step4_assistant_tool_code_interpreter](../getting_started_with_agents/openai_assistant/step4_assistant_tool_code_interpreter.py)|How to use the code-interpreter tool for an OpenAI Assistant agent.
[step5_assistant_tool_file_search](../getting_started_with_agents/openai_assistant/step5_assistant_tool_file_search.py)|How to use the file-search tool for an OpenAI Assistant agent.
[step6_assistant](../getting_started_with_agents/openai_assistant/step6_assistant_declarative.py)|How to create an Assistant Agent from a declarative spec.
## OpenAI Responses Agent
Example|Description
---|---
[step1_responses_agent](../getting_started_with_agents/openai_responses/step1_responses_agent.py)|How to create and use an OpenAI Responses agent in the most simple way.
[step2_responses_agent_thread_management](../getting_started_with_agents/openai_responses/step2_responses_agent_thread_management.py)| How to create and use a `ResponsesAgentThread` agent to maintain conversation context.
[step3_responses_agent_plugins](../getting_started_with_agents/openai_responses/step3_responses_agent_plugins.py)|How to create and use an OpenAI Responses agent with plugins.
[step4_responses_agent_web_search](../getting_started_with_agents/openai_responses/step4_responses_agent_web_search.py)|How to use the web search preview tool with an OpenAI Responses agent.
[step5_responses_agent_file_search](../getting_started_with_agents/openai_responses/step5_responses_agent_file_search.py)|How to use the file-search tool with an OpenAI Responses agent.
[step6_responses_agent_vision](../getting_started_with_agents/openai_responses/step6_responses_agent_vision.py)|How to provide an image as input to an OpenAI Responses agent.
[step7_responses_agent_structured_outputs](../getting_started_with_agents/openai_responses/step7_responses_agent_structured_outputs.py)|How to use have an OpenAI Responses agent use structured outputs.
[step8_assistant](../getting_started_with_agents/openai_responses/step8_responses_agent_declarative.py)|How to create a Responses Agent from a declarative spec.
## Multi-Agent Orchestration
Example|Description
---|---
[step1_concurrent](../getting_started_with_agents/multi_agent_orchestration/step1_concurrent.py)|How to run agents in parallel on the same task.
[step1a_concurrent_structure_output](../getting_started_with_agents/multi_agent_orchestration/step1a_concurrent_structure_output.py)|How to run agents in parallel on the same task and return structured output.
[step2_sequential](../getting_started_with_agents/multi_agent_orchestration/step2_sequential.py)|How to run agents in sequence to complete a task.
[step2a_sequential_cancellation_token](../getting_started_with_agents/multi_agent_orchestration/step2a_sequential_cancellation_token.py)|How to cancel an invocation while it is in progress.
[step3_group_chat](../getting_started_with_agents/multi_agent_orchestration/step3_group_chat.py)|How to run agents in a group chat to complete a task.
[step3a_group_chat_human_in_the_loop](../getting_started_with_agents/multi_agent_orchestration/step3a_group_chat_human_in_the_loop.py)|How to run agents in a group chat with human in the loop.
[step3b_group_chat_with_chat_completion_manager](../getting_started_with_agents/multi_agent_orchestration/step3b_group_chat_with_chat_completion_manager.py)|How to run agents in a group chat with a more dynamic manager.
[step4_handoff](../getting_started_with_agents/multi_agent_orchestration/step4_handoff.py)|How to run agents in a handoff orchestration to complete a task.
[step4a_handoff_structure_input](../getting_started_with_agents/multi_agent_orchestration/step4a_handoff_structure_input.py)|How to run agents in a handoff orchestration to complete a task with structured input.
[step5_magentic](../getting_started_with_agents/multi_agent_orchestration/step5_magentic.py)|How to run agents in a Magentic orchestration to complete a task.
## Configuring the Kernel
Similar to the Semantic Kernel Python concept samples, it is necessary to configure the secrets
and keys used by the kernel. See the follow "Configuring the Kernel" [guide](../concepts/README.md#configuring-the-kernel) for
more information.
## Running Concept Samples
Concept samples can be run in an IDE or via the command line. After setting up the required api key
for your AI connector, the samples run without any extra command line arguments.
@@ -0,0 +1,6 @@
AZURE_AI_AGENT_PROJECT_CONNECTION_STRING = "<example-connection-string>"
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "<example-model-deployment-name>"
AZURE_AI_AGENT_ENDPOINT = "<example-endpoint>"
AZURE_AI_AGENT_SUBSCRIPTION_ID = "<example-subscription-id>"
AZURE_AI_AGENT_RESOURCE_GROUP_NAME = "<example-resource-group-name>"
AZURE_AI_AGENT_PROJECT_NAME = "<example-project-name>"
@@ -0,0 +1,124 @@
## Azure AI Agents
The following getting started samples show how to use Azure AI Agents with Semantic Kernel.
To set up the required resources, follow the "Quickstart: Create a new agent" guide [here](https://learn.microsoft.com/en-us/azure/ai-services/agents/quickstart?pivots=programming-language-python-azure).
You will need to install the optional Semantic Kernel `azure` dependencies if you haven't already via:
```bash
pip install semantic-kernel
```
Before running an Azure AI Agent, modify your .env file to include:
```bash
AZURE_AI_AGENT_ENDPOINT = "<example-endpoint-string>"
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = "<example-deployment-name>"
AZURE_AI_AGENT_API_VERSION = "<example-api-version>"
```
The endpoint can be found listed as part of the Azure Foundry [portal](https://ai.azure.com) in the format of: `https://<resource>.services.ai.azure.com/api/projects/<project-name>`.
The .env should be placed in the root directory.
## Configuring the AI Project Client
Ensure that your Azure AI Agent resources are configured with at least a Basic or Standard SKU.
To begin, create the project client as follows:
```python
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# Your operational code here
```
Before running the example, make sure to run `az login` command in shell using Azure CLI to authenticate and get access to Azure services.
### Required Imports
The required imports for the `Azure AI Agent` include async libraries:
```python
from azure.identity.aio import AzureCliCredential
```
### Initializing the Agent
You can pass in an endpoint, along with an optional api-version, to create the client:
```python
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(
credential=creds,
endpoint=ai_agent_settings.endpoint,
api_version=ai_agent_settings.api_version,
) as client,
):
# operational logic
```
### Creating an Agent Definition
Once the client is initialized, you can define the agent:
```python
# Create agent definition
agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name=AGENT_NAME,
instructions=AGENT_INSTRUCTIONS,
)
```
Then, instantiate the `AzureAIAgent` with the `client` and `agent_definition`:
```python
# Create the AzureAI Agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
```
Now, you can create a thread, add chat messages to the agent, and invoke it with given inputs and optional parameters.
### Reusing an Agent Definition
In certain scenarios, you may prefer to reuse an existing agent definition rather than creating a new one. This can be done by calling `await client.agents.get_agent(...)` instead of `await client.agents.create_agent(...)`.
For a practical example, refer to the [`step7_azure_ai_agent_retrieval`](./step7_azure_ai_agent_retrieval.py) sample.
## Requests and Rate Limits
### Managing API Request Frequency
Your default request limits may be low, affecting how often you can poll the status of a run. You have two options:
1. Adjust the `polling_options` of the `AzureAIAgent`
By default, the polling interval is 250 ms. You can slow it down to 1 second (or another preferred value) to reduce the number of API calls:
```python
# Required imports
from datetime import timedelta
from semantic_kernel.agents.run_polling_options import RunPollingOptions
# Configure the polling options as part of the `AzureAIAgent`
agent = AzureAIAgent(
client=client,
definition=agent_definition,
polling_options=RunPollingOptions(run_polling_interval=timedelta(seconds=1)),
)
```
2. Increase Rate Limits in Azure AI Foundry
You can also adjust your deployment's Rate Limit (Tokens per minute), which impacts the Rate Limit (Requests per minute). This can be configured in Azure AI Foundry under your project's deployment settings for the "Connected Azure OpenAI Service Resource."
@@ -0,0 +1,77 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
"""
The following sample demonstrates how to create an Azure AI agent that answers
user questions. This sample demonstrates the basic steps to create an agent
and simulate a conversation with the agent.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello, I am John Doe.",
"What is your name?",
"What is my name?",
]
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create an agent on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
name="Assistant",
instructions="Answer the user's questions.",
)
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent with the specified message for response
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 6. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: Hello, I am John Doe.
# Assistant: Hello, John! How can I assist you today?
# User: What is your name?
# Assistant: I'm here as your assistant, so you can just call me Assistant. How can I help you today?
# User: What is my name?
# Assistant: Your name is John Doe. How can I assist you today, John?
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,94 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an Azure AI agent that answers
questions about a sample menu using a Semantic Kernel Plugin.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create an agent on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
name="Host",
instructions="Answer questions about the menu.",
)
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
plugins=[MenuPlugin()], # Add the plugin to the agent
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 5. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: Hello
# Agent: Hello! How can I assist you today?
# User: What is the special soup?
# ...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,119 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentGroupChat, AzureAIAgent, AzureAIAgentSettings
from semantic_kernel.agents.strategies import TerminationStrategy
from semantic_kernel.contents import AuthorRole
"""
The following sample demonstrates how to create an OpenAI assistant using either
Azure OpenAI or OpenAI, a chat completion agent and have them participate in a
group chat to work towards the user's requirement.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
return "approved" in history[-1].content.lower()
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved. Do not use the word "approve" unless you are giving approval.
If not, provide insight on how to refine suggested copy without example.
"""
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
TASK = "a slogan for a new line of electric cars."
async def main():
ai_agent_settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create the reviewer agent on the Azure AI agent service
reviewer_agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
)
# 2. Create a Semantic Kernel agent for the reviewer Azure AI agent
agent_reviewer = AzureAIAgent(
client=client,
definition=reviewer_agent_definition,
)
# 3. Create the copy writer agent on the Azure AI agent service
copy_writer_agent_definition = await client.agents.create_agent(
model=ai_agent_settings.model_deployment_name,
name=COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
)
# 4. Create a Semantic Kernel agent for the copy writer Azure AI agent
agent_writer = AzureAIAgent(
client=client,
definition=copy_writer_agent_definition,
)
# 5. Place the agents in a group chat with a custom termination strategy
chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
)
try:
# 6. Add the task as a message to the group chat
await chat.add_chat_message(message=TASK)
print(f"# {AuthorRole.USER}: '{TASK}'")
# 7. Invoke the chat
async for content in chat.invoke():
print(f"# {content.role} - {content.name or '*'}: '{content.content}'")
finally:
# 8. Cleanup: Delete the agents
await chat.reset()
await client.agents.delete_agent(agent_reviewer.id)
await client.agents.delete_agent(agent_writer.id)
"""
Sample Output:
# AuthorRole.USER: 'a slogan for a new line of electric cars.'
# AuthorRole.ASSISTANT - CopyWriter: '"Charge Ahead: Drive the Future."'
# AuthorRole.ASSISTANT - ArtDirector: 'This slogan has a nice ring to it and captures the ...'
# AuthorRole.ASSISTANT - CopyWriter: '"Plug In. Drive Green."'
...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,133 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.ai.agents.models import CodeInterpreterTool, FilePurpose
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import AuthorRole
"""
The following sample demonstrates how to create a simple, Azure AI agent that
uses the code interpreter tool to answer a coding question.
"""
TASK = "What's the total sum of all sales for all segments using Python?"
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create an agent with a code interpreter on the Azure AI agent service
csv_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "sales.csv"
)
# 2. Upload the CSV file to the Azure AI agent service
file = await client.agents.files.upload_and_poll(file_path=csv_file_path, purpose=FilePurpose.AGENTS)
# 3. Create a code interpreter tool referencing the uploaded file
code_interpreter = CodeInterpreterTool(file_ids=[file.id])
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
tools=code_interpreter.definitions,
tool_resources=code_interpreter.resources,
)
# 4. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 5. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 6. Invoke the agent for the specified thread for response
async for response in agent.invoke(messages=TASK, thread=thread):
if response.role != AuthorRole.TOOL:
print(f"# Agent: {response}")
thread = response.thread
finally:
# 7. Cleanup: Delete the thread, agent, and file
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
await client.agents.files.delete(file.id)
"""
Sample Output:
# User: 'Give me the code to calculate the total sales for all segments.'
# AuthorRole.ASSISTANT: Let me first load the uploaded file to understand its contents before providing
tailored code.
```python
import pandas as pd
# Load the uploaded file
file_path = '/mnt/data/assistant-GBaUAF6AKds3sfdfSpxJZG'
data = pd.read_excel(file_path) # Attempting to load as an Excel file initially
# Display the first few rows and understand its structure
data.head(), data.info()
```
# AuthorRole.ASSISTANT: The file format couldn't be automatically determined. Let me attempt to load it as a
CSV or other type.
```python
# Attempt to load the file as a CSV
data = pd.read_csv(file_path)
# Display the first few rows of the dataset and its information
data.head(), data.info()
```
# AuthorRole.ASSISTANT: <class 'pandas.core.frame.DataFrame'>
RangeIndex: 700 entries, 0 to 699
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Segment 700 non-null object
1 Country 700 non-null object
2 Product 700 non-null object
3 Units Sold 700 non-null float64
4 Sale Price 700 non-null float64
5 Gross Sales 700 non-null float64
6 Discounts 700 non-null float64
7 Sales 700 non-null float64
8 COGS 700 non-null float64
9 Profit 700 non-null float64
10 Date 700 non-null object
11 Month Number 700 non-null int64
12 Month Name 700 non-null object
13 Year 700 non-null int64
dtypes: float64(7), int64(2), object(5)
memory usage: 76.7+ KB
The dataset has been successfully loaded and contains information regarding sales, profits, and related metrics
for various segments. To calculate the total sales across all segments, we can use the "Sales" column.
Here's the code to calculate the total sales:
```python
# Calculate the total sales for all segments
total_sales = data['Sales'].sum()
total_sales
```
# AuthorRole.ASSISTANT: The total sales for all segments amount to approximately **118,726,350.29**. Let me
know if you need additional analysis or code for manipulating this data!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,84 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.ai.agents.models import FileInfo, FileSearchTool, VectorStore
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import AuthorRole
"""
The following sample demonstrates how to create a simple, Azure AI agent that
uses a file search tool to answer user questions.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Who is the youngest employee?",
"Who works in sales?",
"I have a customer request, who can help me?",
]
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Read and upload the file to the Azure AI agent service
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "employees.pdf"
)
file: FileInfo = await client.agents.files.upload_and_poll(file_path=pdf_file_path, purpose="assistants")
vector_store: VectorStore = await client.agents.vector_stores.create_and_poll(
file_ids=[file.id], name="my_vectorstore"
)
# 2. Create file search tool with uploaded resources
file_search = FileSearchTool(vector_store_ids=[vector_store.id])
# 3. Create an agent on the Azure AI agent service with the file search tool
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
tools=file_search.definitions,
tool_resources=file_search.resources,
)
# 4. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 5. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 6. Invoke the agent for the specified thread for response
async for response in agent.invoke(messages=user_input, thread=thread):
if response.role != AuthorRole.TOOL:
print(f"# Agent: {response}")
thread = response.thread
finally:
# 7. Cleanup: Delete the thread and agent and other resources
await thread.delete() if thread else None
await client.agents.vector_stores.delete(vector_store.id)
await client.agents.files.delete(file.id)
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Who is the youngest employee?'
# Agent: The youngest employee is Teodor Britton, who is an accountant and was born on January 9, 1997...
# User: 'Who works in sales?'
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,119 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import json
import os
from azure.ai.agents.models import OpenApiAnonymousAuthDetails, OpenApiTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
"""
The following sample demonstrates how to create a simple, Azure AI agent that
uses OpenAPI tools to answer user questions.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"What is the name and population of the country that uses currency with abbreviation THB",
"What is the current weather in the capital city of the country?",
]
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Read in the OpenAPI spec files
openapi_spec_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
"resources",
)
with open(os.path.join(openapi_spec_file_path, "weather.json")) as weather_file:
weather_openapi_spec = json.loads(weather_file.read())
with open(os.path.join(openapi_spec_file_path, "countries.json")) as countries_file:
countries_openapi_spec = json.loads(countries_file.read())
# 2. Create OpenAPI tools
# Note that connection or managed identity auth setup requires additional setup in Azure
auth = OpenApiAnonymousAuthDetails()
openapi_weather = OpenApiTool(
name="get_weather",
spec=weather_openapi_spec,
description="Retrieve weather information for a location",
auth=auth,
)
openapi_countries = OpenApiTool(
name="get_country",
spec=countries_openapi_spec,
description="Retrieve country information",
auth=auth,
)
# 3. Create an agent on the Azure AI agent service with the OpenAPI tools
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
tools=openapi_weather.definitions + openapi_countries.definitions,
)
# 4. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 5. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 7. Invoke the agent for the specified thread for response
async for response in agent.invoke(messages=user_input, thread=thread):
print(f"# Agent: {response}")
thread = response.thread
finally:
# 8. Cleanup: Delete the thread and agent
await client.agents.threads.delete(thread.id) if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'What is the name and population of the country that uses currency with abbreviation THB'
# Agent: It seems I encountered an issue while trying to retrieve data about the country that uses the ...
As of the latest estimates, the population of Thailand is approximately 69 million people. If you ...
# User: 'What is the current weather in the capital city of the country?'
# Agent: The current weather in Bangkok, Thailand, the capital city, is as follows:
- **Temperature**: 24°C (76°F)
- **Feels Like**: 26°C (79°F)
- **Weather Description**: Light rain
- **Humidity**: 69%
- **Cloud Cover**: 75%
- **Pressure**: 1017 hPa
- **Wind Speed**: 8 km/h (5 mph) from the east-northeast (ENE)
- **Visibility**: 10 km (approximately 6 miles)
This weather information reflects the current conditions as of the latest observation. If you need ...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,84 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
"""
The following sample demonstrates how to use an already existing
Azure AI Agent within Semantic Kernel. This sample requires that you
have an existing agent created either previously in code or via the
Azure Portal (or CLI).
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Using the provided doc, tell me about the evolution of RAG.",
]
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Retrieve the agent definition based on the `agent_id`
# Replace the "your-agent-id" with the actual agent ID
# you want to use.
agent_definition = await client.agents.get_agent(
agent_id="<your-agent-id>",
)
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 4. Invoke the agent for the specified thread for response
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
on_intermediate_message=handle_streaming_intermediate_steps,
):
# Print the agent's response
print(f"{response}", end="", flush=True)
# Update the thread for subsequent messages
thread = response.thread
finally:
# 5. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
# Do not clean up the agent so it can be used again
"""
Sample Output:
# User: 'Why is the sky blue?'
# Agent: The sky appears blue because molecules in the Earth's atmosphere scatter sunlight,
and blue light is scattered more than other colors due to its shorter wavelength.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,110 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AgentRegistry, AzureAIAgent, AzureAIAgentSettings
from semantic_kernel.functions import kernel_function
from semantic_kernel.kernel import Kernel
"""
The following sample demonstrates how to create an Azure AI agent that answers
questions about a sample menu using a Semantic Kernel Plugin. The agent is created
using a yaml declarative spec.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Define the YAML string for the sample
SPEC = """
type: foundry_agent
name: Host
instructions: Respond politely to the user's questions.
model:
id: ${AzureAI:ChatModelId}
tools:
- id: MenuPlugin.get_specials
type: function
- id: MenuPlugin.get_item_price
type: function
"""
async def main() -> None:
settings = AzureAIAgentSettings()
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Create a Kernel instance
# For declarative agents, the kernel is required to resolve the plugin(s)
kernel = Kernel()
kernel.add_plugin(MenuPlugin())
# 2. Create a Semantic Kernel agent for the Azure AI agent
agent: AzureAIAgent = await AgentRegistry.create_from_yaml(
SPEC,
kernel=kernel,
settings=settings,
client=client,
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 5. Cleanup: Delete the thread and agent
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: Hello
# Agent: Hello! How can I assist you today?
# User: What is the special soup?
# ...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,119 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.ai.agents.models import McpTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
"""
The following sample demonstrates how to create a simple, Azure AI agent that
uses the mcp tool to connect to an mcp server.
"""
TASK = "Please summarize the Azure REST API specifications Readme"
async def handle_intermediate_messages(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
# 1. Define the MCP tool with the server URL
mcp_tool = McpTool(
server_label="github",
server_url="https://gitmcp.io/Azure/azure-rest-api-specs",
allowed_tools=[], # Specify allowed tools if needed
)
# Optionally you may configure to require approval
# Allowed values are "never" or "always"
mcp_tool.set_approval_mode("never")
# 2. Create an agent with the MCP tool on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
tools=mcp_tool.definitions,
instructions="You are a helpful agent that can use MCP tools to assist users.",
)
# 3. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(
client=client,
definition=agent_definition,
)
# 4. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 5. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=TASK, thread=thread, on_intermediate_message=handle_intermediate_messages
):
print(f"# Agent: {response}")
thread = response.thread
finally:
# 6. Cleanup: Delete the thread, agent, and file
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Please summarize the Azure REST API specifications Readme'
Function Call:> fetch_azure_rest_api_docs with arguments: {}
The Azure REST API specifications Readme provides comprehensive documentation and guidelines for designing,
authoring, validating, and evolving Azure REST APIs. It covers key areas including:
1. Breaking changes and versioning: Guidelines to manage API changes that break backward compatibility, when to
increment API versions, and how to maintain smooth API evolution.
2. OpenAPI/Swagger specifications: How to author REST APIs using OpenAPI specification 2.0 (Swagger), including
structure, conventions, validation tools, and extensions used by AutoRest for generating client SDKs.
3. TypeSpec language: Introduction to TypeSpec, a powerful language for describing and generating REST API
specifications and client SDKs with extensibility to other API styles.
4. Directory structure and uniform versioning: Organizing service specifications by teams, resource provider
namespaces, and following uniform versioning to keep API versions consistent across documentation and SDKs.
5. Validation and tooling: Tools and processes like OAV, AutoRest, RESTler, and CI checks used to validate API
specs, generate SDKs, detect breaking changes, lint specifications, and test service contract accuracy.
6. Authoring best practices: Manual and automated guidelines for quality API spec authoring, including writing
effective descriptions, resource modeling, naming conventions, and examples.
7. Code generation configurations: How to configure readme files to generate SDKs for various languages
including .NET, Java, Python, Go, Typescript, and Azure CLI using AutoRest.
8. API Scenarios and testing: Defining API scenario test files for end-to-end REST API workflows, including
variables, ARM template integration, and usage of test-proxy for recording traffic.
9. SDK automation and release requests: Workflows for SDK generation validation, suppressing breaking change
warnings, and requesting official Azure SDK releases.
Overall, the Readme acts as a central hub providing references, guidelines, examples, and tools for maintaining
high-quality Azure REST API specifications and seamless SDK generation across multiple languages and
platforms. It ensures consistent API design, versioning, validation, and developer experience in the Azure
ecosystem.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,143 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from datetime import timedelta
from azure.ai.agents.models import DeepResearchTool
from azure.identity.aio import AzureCliCredential
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread, RunPollingOptions
from semantic_kernel.contents import AnnotationContent, ChatMessageContent, FunctionCallContent, FunctionResultContent
"""
The following sample demonstrates how to create an AzureAIAgent along
with the Deep Research Tool. Please visit the following documentation for more info
on what is required to run the sample: https://aka.ms/agents-deep-research. Please pay
attention to the purple `Note` boxes in the Azure docs.
Note that when you use your Bing Connection ID, it needs to be the connection ID from the project, not the resource.
It has the following format:
'/subscriptions/<sub_id>/resourceGroups/<rg_name>/providers/<provider_name>/accounts/<account_name>/projects/<project_name>/connections/<connection_name>'
"""
TASK = (
"Research the current state of studies on orca intelligence and orca language, "
"including what is currently known about orcas' cognitive capabilities and communication systems."
)
async def handle_intermediate_messages(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
print()
async def main() -> None:
async with (
AzureCliCredential() as creds,
AzureAIAgent.create_client(credential=creds) as client,
):
azure_ai_agent_settings = AzureAIAgentSettings()
# 1. Define the Deep Research tool
deep_research_tool = DeepResearchTool(
bing_grounding_connection_id=azure_ai_agent_settings.bing_connection_id,
deep_research_model=azure_ai_agent_settings.deep_research_model,
)
# 2. Create an agent with the tool on the Azure AI agent service
agent_definition = await client.agents.create_agent(
model="gpt-4o",
tools=deep_research_tool.definitions,
instructions="You are a helpful Agent that assists in researching scientific topics.",
)
# 3. Create a Semantic Kernel agent for the Azure AI agent
agent = AzureAIAgent(client=client, definition=agent_definition, name="DeepResearchAgent")
# 4. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AzureAIAgentThread | None = None
try:
print(f"# User: '{TASK}'")
# 5. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=TASK,
thread=thread,
on_intermediate_message=handle_intermediate_messages,
polling_options=RunPollingOptions(run_polling_timeout=timedelta(minutes=10)),
):
# Note that the underlying Deep Research Tool uses the o3 reasoning model.
# When using the non-streaming invoke, it is normal for there to be
# several minutes of processing before agent response(s) appear.
# For a fast response, consider using the streaming invoke method.
# A sample exists in the `concepts/agents/azure_ai_agent` directory.
print(f"# {response.name}: {response}")
for item in response.items or []:
if isinstance(item, AnnotationContent):
label = item.title or item.url or (item.quote or "Annotation")
print(f"\n[Annotation] {label} -> {item.url}")
thread = response.thread
finally:
# 6. Cleanup: Delete the thread, agent, and file
await thread.delete() if thread else None
await client.agents.delete_agent(agent.id)
"""
Sample Output:
# User: 'Research the current state of studies on orca intelligence and orca language, including what is
currently known about orcas' cognitive capabilities and communication systems.'
Function Call:> deep_research with arguments: {'input': '{"prompt": "Research the current state of studies on
orca intelligence and orca language. Include up-to-date findings on both their cognitive capabilities and
communication systems. Structure the findings as a detailed report with well-formatted headers that break down
topics such as orcas\' cognitive skills (e.g., problem-solving, memory, and social intelligence), their
language or communication methods (e.g., vocalizations, dialects, and symbolic communication), and comparisons
to other highly intelligent species. Include sources, prioritize recent peer-reviewed studies and reputable
marine biology publications, and ensure the report is well-cited and clear."}'}
# DeepResearchAgent: Got it! I'll gather recent studies and findings on orca intelligence and their
# communication systems, focusing on cognitive abilities and the mechanisms of their language.
# I'll update you with a comprehensive overview soon.
Title: Current Research on Orca Intelligence and Language
Starting deep research...
# DeepResearchAgent: cot_summary: **Examining orca intelligence**
The task involves looking into orca cognitive abilities, communication methods, and comparisons with
other intelligent species. It includes recent peer-reviewed studies and credible sources. 【1†Bing Search】
[Annotation] Bing Search: '2024 orca intelligence cognitive study research' -> https://www.bing.com/search?q=2024%20orca%20intelligence%20cognitive%20study%20research
# DeepResearchAgent: cot_summary: **Investigating orca intelligence**
I'm curious about headlines discussing orcas' cognitive abilities and behaviors, especially their tool use,
recent attacks, and comparisons with dolphins. 【1†Bing Search】
[Annotation] Bing Search: 'orca cognition recent peer-reviewed studies orca communication recent study' -> https://www.bing.com/search?q=orca%20cognition%20recent%20peer-reviewed%20studies%20orca%20communication%20recent%20study
# DeepResearchAgent: cot_summary: **Researching social dynamics**
I'm gathering info on killer whale social dynamics from what appears to be a 2024 article on ResearchGate.
# DeepResearchAgent: cot_summary: **Assessing publication type**
I'm exploring if the ResearchGate link points to a preprint, student paper, or journal article.
Progress is steady as I look into its initiation and source.
# DeepResearchAgent: cot_summary: **Investigating PDF issues**
...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,44 @@
# Chat Completion Agents
The following samples demonstrate how to get started with Chat Completion Agents using Semantic Kernel.
## Configuring a Chat Completion Agent
The `ChatCompletionAgent` relies on an underlying AI service connector. Depending on the AI service you choose, you may need to install additional packages. Refer to the [official SK documentation](https://learn.microsoft.com/en-us/semantic-kernel/concepts/ai-services/chat-completion/?tabs=csharp-AzureOpenAI%2Cpython-AzureOpenAI%2Cjava-AzureOpenAI&pivots=programming-language-python#installing-the-necessary-packages-1) for guidance on which extras are required.
Next, follow this [configuration guide](../../concepts/README.md#configuring-the-kernel) to set up your environment for running the sample code.
If you're developing outside the Semantic Kernel repository, it's recommended to place your `.env` file at the root of your project. When using VSCode, this allows the IDE to automatically load the `.env` file and make the environment variables available to your application.
This setup enables the following code to work without explicitly passing keyword arguments to the AI service constructor:
```python
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
agent = ChatCompletionAgent(
service=AzureChatCompletion(), # No explicit kwargs needed due to environment variable configuration
name="Assistant",
instructions="Answer questions about the world in one sentence.",
)
```
If you prefer to configure the service manually, you can do the following:
```python
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
agent = ChatCompletionAgent(
service=AzureChatCompletion(
api_key="your-api-key",
endpoint="your-aoai-endpoint",
deployment_name="your-deployment-name",
api_version="2025-03-01-preview" # Replace with your desired API version
),
name="Assistant",
instructions="Answer questions about the world in one sentence.",
)
```
For more information about the `ChatCompletionAgent` see Semantic Kernel's official documentation [here](https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/chat-completion-agent?pivots=programming-language-python).
@@ -0,0 +1,56 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to create a chat completion agent that
answers user questions using the Azure Chat Completion service. The Chat Completion
Service is passed directly via the ChatCompletionAgent constructor. This sample
demonstrates the basic steps to create an agent and simulate a conversation
with the agent.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Why is the sky blue?",
"What is the capital of France?",
]
async def main():
# 1. Create the agent by specifying the service
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Assistant",
instructions="Answer questions about the world in one sentence.",
)
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 2. Invoke the agent for a response
response = await agent.get_response(
messages=user_input,
)
# 3. Print the response
print(f"# {response.name}: {response}")
"""
Sample output:
# User: Why is the sky blue?
# Assistant: The sky appears blue because molecules in the Earth's atmosphere scatter shorter wavelengths of
sunlight, like blue, more than the longer wavelengths, causing the sky to look blue to our eyes.
# User: What is the capital of France?
# Assistant: The capital of France is Paris.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,73 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import (
ChatCompletionAgent,
ChatHistoryAgentThread,
)
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to create a chat completion agent that
answers user questions using the Azure Chat Completion service. The Chat Completion
Service is passed directly via the ChatCompletionAgent constructor. This sample
demonstrates the basic steps to create an agent and simulate a conversation
with the agent.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history needs to be maintained by the caller in the chat history object.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello, I am John Doe.",
"What is your name?",
"What is my name?",
]
async def main():
# 1. Create the agent by specifying the service
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Assistant",
instructions="Answer the user's questions.",
)
# 2. Create a thread to hold the conversation
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 3. Invoke the agent for a response
response = await agent.get_response(
messages=user_input,
thread=thread,
)
print(f"# {response.name}: {response}")
# 4. Store the thread, which allows the agent to
# maintain conversation history across multiple messages.
thread = response.thread
# 5. Cleanup: Clear the thread
await thread.delete() if thread else None
"""
Sample output:
# User: Hello, I am John Doe.
# Assistant: Hello, John Doe! How can I assist you today?
# User: What is your name?
# Assistant: I don't have a personal name like a human does, but you can call me Assistant.?
# User: What is my name?
# Assistant: You mentioned that your name is John Doe. How can I assist you further, John?
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,75 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel import Kernel
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to create a chat completion agent that
answers user questions using the Azure Chat Completion service. The Chat Completion
Service is first added to the kernel, and the kernel is passed in to the
ChatCompletionAgent constructor. This sample demonstrates the basic steps to
create an agent and simulate a conversation with the agent.
Note: if both a service and a kernel are provided, the service will be used.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history needs to be maintained by the caller in the chat history object.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello, I am John Doe.",
"What is your name?",
"What is my name?",
]
async def main():
# 1. Create the instance of the Kernel to register an AI service
kernel = Kernel()
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
# 2. Create the agent
agent = ChatCompletionAgent(
kernel=kernel,
name="Assistant",
instructions="Answer the user's questions.",
)
# 3. Create a thread to hold the conversation
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent for a response
response = await agent.get_response(
messages=user_input,
thread=thread,
)
print(f"# {response.name}: {response}")
thread = response.thread
# 4. Cleanup: Clear the thread
await thread.delete() if thread else None
"""
Sample output:
# User: Hello, I am John Doe.
# Assistant: Hello, John Doe! How can I assist you today?
# User: What is your name?
# Assistant: I don't have a personal name like a human does, but you can call me Assistant.?
# User: What is my name?
# Assistant: You mentioned that your name is John Doe. How can I assist you further, John?
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,86 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a chat completion agent that
answers questions about a sample menu using a Semantic Kernel Plugin. The Chat
Completion Service is passed directly via the ChatCompletionAgent constructor.
Additionally, the plugin is supplied via the constructor.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"What does that cost?",
"Thank you",
]
async def main():
# 1. Create the agent
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Host",
instructions="Answer questions about the menu.",
plugins=[MenuPlugin()],
)
# 2. Create a thread to hold the conversation
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent for a response
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response} ")
thread = response.thread
# 4. Cleanup: Clear the thread
await thread.delete() if thread else None
"""
Sample output:
# User: Hello
# Host: Hello! How can I assist you today?
# User: What is the special soup?
# Host: The special soup is Clam Chowder.
# User: What does that cost?
# Host: The special soup, Clam Chowder, costs $9.99.
# User: Thank you
# Host: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,102 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel import Kernel
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.functions import KernelArguments, kernel_function
"""
The following sample demonstrates how to create a chat completion agent that
answers questions about a sample menu using a Semantic Kernel Plugin. The Chat
Completion Service is first added to the kernel, and the kernel is passed in to the
ChatCompletionAgent constructor. Additionally, the plugin is supplied via the kernel.
To enable auto-function calling, the prompt execution settings are retrieved from the kernel
using the specified `service_id`. The function choice behavior is set to `Auto` to allow the
agent to automatically execute the plugin's functions when needed.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"What does that cost?",
"Thank you",
]
async def main():
# 1. Create the instance of the Kernel to register the plugin and service
service_id = "agent"
kernel = Kernel()
kernel.add_plugin(MenuPlugin(), plugin_name="menu")
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=AzureCliCredential()))
# 2. Configure the function choice behavior to auto invoke kernel functions
# so that the agent can automatically execute the menu plugin functions when needed
settings = kernel.get_prompt_execution_settings_from_service_id(service_id=service_id)
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
# 3. Create the agent
agent = ChatCompletionAgent(
kernel=kernel,
name="Host",
instructions="Answer questions about the menu.",
arguments=KernelArguments(settings=settings),
)
# 4. Create a thread to hold the conversation
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 5. Invoke the agent for a response
async for response in agent.invoke(messages=user_input, thread=thread):
print(f"# {response.name}: {response}")
thread = response.thread
# 6. Cleanup: Clear the thread
await thread.delete() if thread else None
"""
Sample output:
# User: Hello
# Host: Hello! How can I assist you today?
# User: What is the special soup?
# Host: The special soup is Clam Chowder.
# User: What does that cost?
# Host: The special soup, Clam Chowder, costs $9.99.
# User: Thank you
# Host: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,110 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel import Kernel
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.agents.strategies import TerminationStrategy
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to create a simple, agent group chat that
utilizes An Art Director Chat Completion Agent along with a Copy Writer Chat
Completion Agent to complete a task.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
def _create_kernel_with_chat_completion(service_id: str) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=AzureCliCredential()))
return kernel
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
last_message = history[-1].content.lower()
return "approved" in last_message and "not approved" not in last_message
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved.
If not, provide insight on how to refine suggested copy without example.
"""
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
TASK = "a slogan for a new line of electric cars."
async def main():
# 1. Create the reviewer agent based on the chat completion service
agent_reviewer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("artdirector"),
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
)
# 2. Create the copywriter agent based on the chat completion service
agent_writer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("copywriter"),
name=COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
)
# 3. Place the agents in a group chat with a custom termination strategy
group_chat = AgentGroupChat(
agents=[
agent_writer,
agent_reviewer,
],
termination_strategy=ApprovalTerminationStrategy(
agents=[agent_reviewer],
maximum_iterations=10,
),
)
# 4. Add the task as a message to the group chat
await group_chat.add_chat_message(message=TASK)
print(f"# User: {TASK}")
# 5. Invoke the chat
async for content in group_chat.invoke():
print(f"# {content.name}: {content.content}")
"""
Sample output:
# User: a slogan for a new line of electric cars.
# CopyWriter: "Drive the Future: Shockingly Efficient."
# ArtDirector: This slogan has potential but could benefit from refinement to create a stronger ...
# CopyWriter: "Electrify Your Drive."
# ArtDirector: Approved. This slogan is concise, memorable, and effectively communicates the ...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,145 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel import Kernel
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.agents.strategies import KernelFunctionSelectionStrategy, KernelFunctionTerminationStrategy
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.functions import KernelFunctionFromPrompt
"""
The following sample demonstrates how to create a simple, agent group chat that utilizes
An Art Director Chat Completion Agent along with a Copy Writer Chat Completion Agent to
complete a task. The sample also shows how to specify a Kernel Function termination and
selection strategy to determine when to end the chat or how to select the next agent to
take a turn in the conversation.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
def _create_kernel_with_chat_completion(service_id: str) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=AzureCliCredential()))
return kernel
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved.
If not, provide insight on how to refine suggested copy without example.
"""
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
TASK = "a slogan for a new line of electric cars."
async def main():
# 1. Create the reviewer agent based on the chat completion service
agent_reviewer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("artdirector"),
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
)
# 2. Create the copywriter agent based on the chat completion service
agent_writer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("copywriter"),
name=COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
)
# 3. Create a Kernel Function to determine if the copy has been approved
termination_function = KernelFunctionFromPrompt(
function_name="termination",
prompt="""
Determine if the copy has been approved. If so, respond with a single word: yes
History:
{{$history}}
""",
)
# 4. Create a Kernel Function to determine which agent should take the next turn
selection_function = KernelFunctionFromPrompt(
function_name="selection",
prompt=f"""
Determine which participant takes the next turn in a conversation based on the the most recent participant.
State only the name of the participant to take the next turn.
No participant should take more than one turn in a row.
Choose only from these participants:
- {REVIEWER_NAME}
- {COPYWRITER_NAME}
Always follow these rules when selecting the next participant:
- After user input, it is {COPYWRITER_NAME}'s turn.
- After {COPYWRITER_NAME} replies, it is {REVIEWER_NAME}'s turn.
- After {REVIEWER_NAME} provides feedback, it is {COPYWRITER_NAME}'s turn.
History:
{{{{$history}}}}
""",
)
# 5. Place the agents in a group chat with the custom termination and selection strategies
chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=KernelFunctionTerminationStrategy(
agents=[agent_reviewer],
function=termination_function,
kernel=_create_kernel_with_chat_completion("termination"),
result_parser=lambda result: str(result.value[0]).lower() == "yes",
history_variable_name="history",
maximum_iterations=10,
),
selection_strategy=KernelFunctionSelectionStrategy(
function=selection_function,
kernel=_create_kernel_with_chat_completion("selection"),
result_parser=lambda result: str(result.value[0]) if result.value is not None else COPYWRITER_NAME,
agent_variable_name="agents",
history_variable_name="history",
),
)
# 6. Add the task as a message to the group chat
await chat.add_chat_message(message=TASK)
print(f"# User: {TASK}")
# 7. Invoke the chat
async for content in chat.invoke():
print(f"# {content.name}: {content.content}")
"""
Sample Output:
# User: a slogan for a new line of electric cars.
# CopyWriter: "Electrify your drive. Spare the gas, not the thrill."
# ArtDirector: This slogan captures the essence of electric cars but could use refinement to ...
# CopyWriter: "Go electric. Enjoy the thrill. Skip the gas."
# ArtDirector: Approved. This slogan is clear, concise, and effectively communicates the ...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,111 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from pydantic import BaseModel, ValidationError
from semantic_kernel import Kernel
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.agents.strategies import TerminationStrategy
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAIChatPromptExecutionSettings
from semantic_kernel.functions import KernelArguments
"""
The following sample demonstrates how to configure an Agent Group Chat, and invoke an
agent with only a single turn.A custom termination strategy is provided where the model
is to rate the user input on creativity and expressiveness and end the chat when a score
of 70 or higher is provided.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
def _create_kernel_with_chat_completion(service_id: str) -> Kernel:
kernel = Kernel()
kernel.add_service(OpenAIChatCompletion(service_id=service_id))
return kernel
class InputScore(BaseModel):
"""A model for the input score."""
score: int
notes: str
class ThresholdTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
threshold: int = 70
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
try:
result = InputScore.model_validate_json(history[-1].content or "")
return result.score >= self.threshold
except ValidationError:
return False
INSTRUCTION = """
Think step-by-step and rate the user input on creativity and expressiveness from 1-100 with some notes on improvements.
"""
# Simulate a conversation with the agent
USER_INPUTS = {
"The sunset is very colorful.",
"The sunset is setting over the mountains.",
"The sunset is setting over the mountains and fills the sky with a deep red flame, setting the clouds ablaze.",
}
async def main():
# 1. Create the instance of the Kernel to register a service
service_id = "agent"
kernel = _create_kernel_with_chat_completion(service_id)
# 2. Configure the prompt execution settings to return the score in the desired format
settings = kernel.get_prompt_execution_settings_from_service_id(service_id)
assert isinstance(settings, OpenAIChatPromptExecutionSettings) # nosec
settings.response_format = InputScore
# 3. Create the agent
agent = ChatCompletionAgent(
kernel=kernel,
name="Tutor",
instructions=INSTRUCTION,
arguments=KernelArguments(settings),
)
# 4. Create the group chat with the custom termination strategy
group_chat = AgentGroupChat(termination_strategy=ThresholdTerminationStrategy(maximum_iterations=10))
for user_input in USER_INPUTS:
# 5. Add the user input to the chat history
await group_chat.add_chat_message(message=user_input)
print(f"# User: {user_input}")
# 6. Invoke the chat with the agent for a response
async for content in group_chat.invoke_single_turn(agent):
print(f"# {content.name}: {content.content}")
"""
Sample output:
# User: The sunset is very colorful.
# Tutor: {"score":45,"notes":"The sentence 'The sunset is very colorful' is simple and direct. While it ..."}
# User: The sunset is setting over the mountains.
# Tutor: {"score":50,"notes":"This sentence provides a basic scene of a sunset over mountains, which ..."}
# User: The sunset is setting over the mountains and fills the sky with a deep red flame, setting the clouds ablaze.
# Tutor: {"score":75,"notes":"This sentence demonstrates improved creativity and expressiveness by ..."}
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,123 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from azure.identity import AzureCliCredential
from semantic_kernel import Kernel
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
from semantic_kernel.agents.strategies import TerminationStrategy
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to create a simple, agent group chat that
utilizes An Art Director Chat Completion Agent along with a Copy Writer Chat
Completion Agent to complete a task. The main point of this sample is to note
how to enable logging to view all interactions between the agents and the model.
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
Read more about the `GroupChatOrchestration` here:
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
"""
# 0. Enable logging
# NOTE: This is all that is required to enable logging.
# Set the desired level to INFO, DEBUG, etc.
logging.basicConfig(level=logging.INFO)
class ApprovalTerminationStrategy(TerminationStrategy):
"""A strategy for determining when an agent should terminate."""
async def should_agent_terminate(self, agent, history):
"""Check if the agent should terminate."""
return "approved" in history[-1].content.lower()
def _create_kernel_with_chat_completion(service_id: str) -> Kernel:
kernel = Kernel()
kernel.add_service(AzureChatCompletion(service_id=service_id, credential=AzureCliCredential()))
return kernel
REVIEWER_NAME = "ArtDirector"
REVIEWER_INSTRUCTIONS = """
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine if the given copy is acceptable to print.
If so, state that it is approved.
If not, provide insight on how to refine suggested copy without example.
"""
COPYWRITER_NAME = "CopyWriter"
COPYWRITER_INSTRUCTIONS = """
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
The goal is to refine and decide on the single best copy as an expert in the field.
Only provide a single proposal per response.
You're laser focused on the goal at hand.
Don't waste time with chit chat.
Consider suggestions when refining an idea.
"""
TASK = "a slogan for a new line of electric cars."
async def main():
# 1. Create the reviewer agent based on the chat completion service
agent_reviewer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("artdirector"),
name=REVIEWER_NAME,
instructions=REVIEWER_INSTRUCTIONS,
)
# 2. Create the copywriter agent based on the chat completion service
agent_writer = ChatCompletionAgent(
kernel=_create_kernel_with_chat_completion("copywriter"),
name=COPYWRITER_NAME,
instructions=COPYWRITER_INSTRUCTIONS,
)
# 3. Place the agents in a group chat with a custom termination strategy
group_chat = AgentGroupChat(
agents=[agent_writer, agent_reviewer],
termination_strategy=ApprovalTerminationStrategy(agents=[agent_reviewer], maximum_iterations=10),
)
# 4. Add the task as a message to the group chat
await group_chat.add_chat_message(message=TASK)
print(f"# User: {TASK}")
# 5. Invoke the chat
async for content in group_chat.invoke():
print(f"# {content.name}: {content.content}")
"""
Sample output:
INFO:semantic_kernel.agents.group_chat.agent_chat:Adding `1` agent chat messages
# User: a slogan for a new line of electric cars.
INFO:semantic_kernel.agents.strategies.selection.sequential_selection_strategy:Selected agent at index 0 (ID: ...
INFO:semantic_kernel.agents.group_chat.agent_chat:Invoking agent CopyWriter
INFO:semantic_kernel.utils.telemetry.model_diagnostics.decorators:{"role": "system", "content": "\nYou are a ...
INFO:semantic_kernel.utils.telemetry.model_diagnostics.decorators:{"role": "user", "content": "a slogan for ...
INFO:semantic_kernel.connectors.ai.open_ai.services.open_ai_handler:OpenAI usage: CompletionUsage(completion_...
INFO:semantic_kernel.utils.telemetry.model_diagnostics.decorators:{"message": {"role": "assistant", "content": ...
INFO:semantic_kernel.agents.chat_completion.chat_completion_agent:[ChatCompletionAgent] Invoked AzureChatCompl...
INFO:semantic_kernel.agents.strategies.termination.termination_strategy:Evaluating termination criteria for ...
INFO:semantic_kernel.agents.strategies.termination.termination_strategy:Agent 598d827e-ce5e-44fa-879b-42793bb...
# CopyWriter: "Drive Change. Literally."
INFO:semantic_kernel.agents.strategies.selection.sequential_selection_strategy:Selected agent at index 1 (ID: ...
INFO:semantic_kernel.agents.group_chat.agent_chat:Invoking agent ArtDirector
INFO:semantic_kernel.utils.telemetry.model_diagnostics.decorators:{"role": "system", "content": "\nYou are an ...
INFO:semantic_kernel.utils.telemetry.model_diagnostics.decorators:{"role": "user", "content": "a slogan for a ...
INFO:semantic_kernel.utils.telemetry.model_diagnostics.decorators:{"role": "assistant", "content": "\"Drive ...
...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,110 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import json
from azure.identity import AzureCliCredential
from pydantic import BaseModel
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureChatPromptExecutionSettings
from semantic_kernel.functions.kernel_arguments import KernelArguments
"""
The following sample demonstrates how to create a chat completion agent that
answers user questions using structured outputs. The `Reasoning` model is defined
on the prompt execution settings. The settings are then passed into the agent
via the `KernelArguments` object.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history needs to be maintained by the caller in the chat history object.
"""
# Define the BaseModel we will use for structured outputs
class Step(BaseModel):
explanation: str
output: str
class Reasoning(BaseModel):
steps: list[Step]
final_answer: str
# Simulate a conversation with the agent
USER_INPUT = "how can I solve 8x + 7y = -23, and 4x=12?"
async def main():
# 1. Create the prompt settings
settings = AzureChatPromptExecutionSettings()
settings.response_format = Reasoning
# 2. Create the agent by specifying the service
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=AzureCliCredential()),
name="Assistant",
instructions="Answer the user's questions.",
arguments=KernelArguments(settings=settings),
)
# 3. Create a thread to hold the conversation
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: ChatHistoryAgentThread = None
print(f"# User: {USER_INPUT}")
# 4. Invoke the agent for a response
response = await agent.get_response(messages=USER_INPUT, thread=thread)
# 5. Validate the response and print the structured output
reasoned_result = Reasoning.model_validate(json.loads(response.message.content))
print(f"# {response.name}:\n\n{reasoned_result.model_dump_json(indent=4)}")
# 6. Cleanup: Clear the thread
await thread.delete() if thread else None
"""
Sample output:
# User: how can I solve 8x + 7y = -23, and 4x=12?
# Assistant:
{
"steps": [
{
"explanation": "The second equation 4x = 12 can be solved for x by dividing both sides by 4.",
"output": "x = 3."
},
{
"explanation": "Substitute x = 3 from the second equation into the first equation 8x + 7y = -23.",
"output": "8(3) + 7y = -23."
},
{
"explanation": "Calculate 8 times 3 to simplify the equation.",
"output": "24 + 7y = -23."
},
{
"explanation": "Subtract 24 from both sides to isolate the term with y.",
"output": "7y = -23 - 24."
},
{
"explanation": "Perform the subtraction.",
"output": "7y = -47."
},
{
"explanation": "Divide both sides by 7 to solve for y.",
"output": "y = -47 / 7."
},
{
"explanation": "Simplify the division to get the value of y.",
"output": "y = -6.714285714285714 (approximately -6.71)."
}
],
"final_answer": "The solution to the system of equations is x = 3 and y = -6.71."
}
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,126 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from pydantic import BaseModel
from semantic_kernel import Kernel
from semantic_kernel.agents import AgentRegistry, ChatHistoryAgentThread
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import (
AzureChatCompletion,
AzureChatPromptExecutionSettings,
)
from semantic_kernel.functions import KernelArguments, kernel_function
"""
The following sample demonstrates how to create a chat completion agent using a
declarative approach. The Chat Completion Agent is created from a YAML spec,
with a specific service and plugins. The agent is then used to answer user questions.
This sample also demonstrates how to properly pass execution settings (like response format)
when using AgentRegistry.create_from_yaml().
"""
# Example structure for structured output
class StructuredResult(BaseModel):
"""Example structure for demonstrating response format."""
response: str
category: str
# 1. Define a Sample Plugin
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# 2. Define the YAML string
AGENT_YAML = """
type: chat_completion_agent
name: Assistant
description: A helpful assistant.
instructions: Answer the user's questions using the menu functions.
tools:
- id: MenuPlugin.get_specials
type: function
- id: MenuPlugin.get_item_price
type: function
model:
options:
temperature: 0.7
"""
# 3. Define your simulated conversation
USER_INPUTS = [
"Hello",
"What is the special soup?",
"What does that cost?",
"Thank you",
]
async def main():
# 4. Create a Kernel and add the plugin
# For declarative agents, the kernel is required to resolve the plugin
kernel = Kernel()
kernel.add_plugin(MenuPlugin(), plugin_name="MenuPlugin")
# 5. Create execution settings with structured output
execution_settings = AzureChatPromptExecutionSettings()
execution_settings.response_format = StructuredResult
# 6. Create KernelArguments with the execution settings
arguments = KernelArguments(settings=execution_settings)
# 7. Create the agent from YAML + inject the AI service
agent: ChatCompletionAgent = await AgentRegistry.create_from_yaml(
AGENT_YAML, kernel=kernel, service=AzureChatCompletion(credential=AzureCliCredential()), arguments=arguments
)
# 8. Create a thread to hold the conversation
thread: ChatHistoryAgentThread | None = None
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 9. Invoke the agent for a response
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response}")
thread = response.thread
# 10. Cleanup the thread
await thread.delete() if thread else None
"""
# Sample output:
# User: Hello
# Assistant: {"response":"Hello! How can I help you today? If you have any questions about the menu, feel free to ask!","category":"Greeting"}
# User: What is the special soup?
# Assistant: {"response":"Today's special soup is Clam Chowder. Would you like to know more about it or see other specials?","category":"Menu Specials"}
# User: What does that cost?
# Assistant: {"response":"The Clam Chowder special soup costs $9.99.","category":"Menu Pricing"}
# User: Thank you
# Assistant: {"response":"You're welcome! If you have any more questions or need assistance with the menu, just let me know. Enjoy your meal!","category":"Polite Closing"}
""" # noqa: E501
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,95 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.core_plugins import SessionsPythonTool
"""
The following sample demonstrates how to create a chat completion agent with
code interpreter capabilities using the Azure Container Apps session pool service.
"""
async def handle_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"# Function Result:> {item.result}")
elif isinstance(item, FunctionCallContent):
print(f"# Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"# {message.name}: {message} ")
async def main():
credential = AzureCliCredential()
# Define the resources directory for file uploads
resources_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources")
# 1. Create the python code interpreter tool using the SessionsPythonTool
# allowed_upload_directories restricts which local directories can be accessed for uploads
python_code_interpreter = SessionsPythonTool(
credential=credential,
allowed_upload_directories=[resources_dir],
)
# 2. Create the agent
agent = ChatCompletionAgent(
service=AzureChatCompletion(credential=credential),
name="Host",
instructions="Answer questions about the menu.",
plugins=[python_code_interpreter],
)
# 3. Upload a CSV file to the session
csv_file_path = os.path.join(resources_dir, "sales.csv")
file_metadata = await python_code_interpreter.upload_file(local_file_path=csv_file_path)
# 4. Invoke the agent for a response to a task
TASK = (
"What's the total sum of all sales for all segments using Python? "
f"Use the uploaded file {file_metadata.full_path} for reference."
)
print(f"# User: '{TASK}'")
async for response in agent.invoke(
messages=TASK,
on_intermediate_message=handle_intermediate_steps,
):
print(f"# {response.name}: {response} ")
"""
Sample output:
# User: 'What's the total sum of all sales for all segments using Python?
Use the uploaded file /mnt/data/sales.csv for reference.'
# Function Call:> SessionsPythonTool-execute_code with arguments: {
"code": "
import pandas as pd
# Load the sales data
file_path = '/mnt/data/sales.csv'
sales_data = pd.read_csv(file_path)
# Calculate the total sum of sales
# Assuming there's a column named 'Sales' which contains the sales amounts
total_sales = sales_data['Sales'].sum()
total_sales"
}
# Function Result:> Status:
Success
Result:
118726350.28999999
Stdout:
Stderr:
# Host: The total sum of all sales for all segments is approximately $118,726,350.29.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,119 @@
# Semantic Kernel - CopilotStudioAgent Quickstart
This README provides an overview on how to use the [CopilotStudioAgent](../../../semantic_kernel/agents/copilot_studio/copilot_studio_agent.py) within Semantic Kernel.
This agent allows you to interact with Microsoft Copilot Studio agents through programmatic APIs.
> ️ **Note:** Knowledge sources must be configured **within** Microsoft Copilot Studio first. Streaming responses are **not currently supported**.
---
## 🔧 Prerequisites
1. Python 3.10+
2. Install Semantic Kernel with Copilot Studio dependencies:
```bash
pip install semantic-kernel
pip install microsoft-agents-hosting-core microsoft-agents-copilotstudio-client
```
3. An agent created in **Microsoft Copilot Studio**
4. Ability to create an application identity in Azure for a **Public Client/Native App Registration**,
or access to an existing app registration with the `CopilotStudio.Copilots.Invoke` API permission assigned.
## Create a Copilot Agent in Copilot Studio
1. Go to [Microsoft Copilot Studio](https://copilotstudio.microsoft.com).
2. Create a new **Agent**.
3. Publish your newly created Agent.
4. In Copilot Studio, navigate to:
`Settings` → `Advanced` → `Metadata`
Save the following values:
- `Schema Name` (maps to `agent_identifier`)
- `Environment ID`
## Create an Application Registration in Entra ID User Interactive Login
> This step requires permissions to create application identities in your Azure tenant.
You will create a **Native Client Application Identity** (no client secret required).
1. Open [Azure Portal](https://portal.azure.com)
2. Navigate to **Entra ID**
3. Go to **App registrations** → **New registration**
4. Fill out:
- **Name**: Any name you like
- **Supported account types**: `Accounts in this organization directory only`
- **Redirect URI**:
- Platform: `Public client/native (mobile & desktop)`
- URI: `http://localhost`
5. Click **Register**
6. From the **Overview** page, note:
- `Application (client) ID`
- `Directory (tenant) ID`
7. Go to: `Manage` → `API permissions`
- Click **Add permission**
- Choose **APIs my organization uses**
- Search for: **Power Platform API**
If it's not listed, see **Tip** below.
8. Choose:
- **Delegated Permissions**
- Expand `CopilotStudio`
- Select `CopilotStudio.Copilots.Invoke`
9. Click **Add permissions**
10. (Optional) Click **Grant admin consent**
### Tip
If you **do not see Power Platform API**, follow [Step 2 in Power Platform API Authentication](https://learn.microsoft.com/en-us/power-platform/admin/programmability-authentication-v2) to add the API to your tenant.
---
### Configure the Example Application - User Interactive Login
Once you've collected all required values:
1. Set the following environment variables in your terminal or .env file:
```env
COPILOT_STUDIO_AGENT_APP_CLIENT_ID=<your-app-client-id>
COPILOT_STUDIO_AGENT_TENANT_ID=<your-tenant-id>
COPILOT_STUDIO_AGENT_ENVIRONMENT_ID=<your-env-id>
COPILOT_STUDIO_AGENT_AGENT_IDENTIFIER=<your-agent-id>
COPILOT_STUDIO_AGENT_AUTH_MODE=interactive
```
## Create an Application Registration in Entra ID Service Principal Login
> **Warning**: Service Principal login is **not yet supported** in the current version of the `CopilotStudioClient`.
## Creating a `CopilotStudioAgent` Client
If all required environment variables are set correctly, you don't need to manually create or pass a `client`. Semantic Kernel will automatically construct the client using the environment configuration.
However, if you need to override any environment variables—such as when specifying custom credentials or cloud settings—you should create the `client` explicitly using `CopilotStudioAgent.create_client(...)` and then pass it to the agent constructor.
```python
client: CopilotClient = CopilotStudioAgent.create_client(
auth_mode: CopilotStudioAgentAuthMode | Literal["interactive", "service"] | None = None,
agent_identifier: str | None = None,
app_client_id: str | None = None,
client_secret: str | None = None,
client_certificate: str | None = None,
cloud: PowerPlatformCloud | None = None,
copilot_agent_type: AgentType | None = None,
custom_power_platform_cloud: str | None = None,
env_file_encoding: str | None = None,
env_file_path: str | None = None,
environment_id: str | None = None,
tenant_id: str | None = None,
user_assertion: str | None = None,
)
agent = CopilotStudioAgent(
client=client,
name="<name>",
instructions="<instructions>",
)
```
@@ -0,0 +1,50 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import CopilotStudioAgent
"""
This sample demonstrates how to use the Copilot Studio agent to answer questions about physics.
It does not use a thread to maintain context between user inputs.
"""
async def main() -> None:
# 1. Create the agent
agent = CopilotStudioAgent(
name="PhysicsAgent",
instructions="You help answer questions about physics. ",
)
# 2. Create a list of user inputs
USER_INPUTS = [
"Why is the sky blue?",
"What is the speed of light?",
]
# 3. Loop through the user inputs and get responses from the agent
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
response = await agent.get_response(messages=user_input)
print(f"# {response.name}: {response}")
"""
Sample output:
# User: Why is the sky blue?
# PhysicsAgent: The sky appears blue because of the way Earth's atmosphere scatters sunlight.
When sunlight enters the atmosphere, it is made up of different colors, each with different wavelengths.
Blue light has shorter wavelengths and is scattered in all directions by the gases and particles in the
atmosphere more than other colors. This scattered blue light is what we see when we look up at the sky.
This phenomenon is known as Rayleigh scattering.
AI-generated content may be incorrect
# User: What is the speed of light?
# PhysicsAgent: The speed of light in a vacuum is approximately 299,792,458 meters per second (m/s). This is often
rounded to 300,000 kilometers per second (km/s) for simplicity.
AI-generated content may be incorrect
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,82 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from microsoft_agents.copilotstudio.client import (
CopilotClient,
)
from semantic_kernel.agents import CopilotStudioAgent, CopilotStudioAgentThread
"""
This sample demonstrates how to use the Copilot Studio agent to answer questions from the user.
It demonstrates how to use a thread to maintain context between user inputs.
"""
async def main() -> None:
# As an example, manually create the client and pass it in to the agent
# 1. Create the client
client: CopilotClient = CopilotStudioAgent.create_client(auth_mode="interactive")
# 2. Create the agent
agent = CopilotStudioAgent(
client=client,
name="PhysicsAgent",
instructions="You are help answer questions about physics.",
)
# 3. Create a list of user inputs
USER_INPUTS = [
"Hello! Who are you? My name is John Doe.",
"What is the speed of light?",
"What have we been talking about?",
"What is my name?",
]
# 4. Create a thread to maintain context between user inputs
# If no thread is provided, a new thread will be created
# and returned in the response
thread: CopilotStudioAgentThread | None = None
# 5. Loop through the user inputs and get responses from the agent
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response}")
thread = response.thread
# 6. If a thread was created, delete it when done
if thread:
await thread.delete()
"""
Sample output:
# User: Hello! Who are you? My name is John Doe.
# PhysicsAgent: Hello, John! I'm an AI assistant here to help you with any questions you might have.
How can I assist you today?
AI-generated content may be incorrect
# User: What is the speed of light?
# PhysicsAgent: The speed of light in a vacuum is approximately 299,792,458 meters per second (m/s).
This is often rounded to 300,000 kilometers per second (km/s) for simplicity. If you have any more questions,
feel free to ask!
AI-generated content may be incorrect
# User: What have we been talking about?
# PhysicsAgent: Sure, John! So far, we've had the following conversation:
1. You introduced yourself and asked who I am.
2. I introduced myself as an AI assistant and asked how I could assist you.
3. You asked about the speed of light, and I provided the information that it is approximately 299,792,458 meters
per second in a vacuum.
If you have any more questions or need further assistance, feel free to ask!
AI-generated content may be incorrect
# User: What is my name?
# PhysicsAgent: Based on our conversation, your name is John Doe. How can I assist you further today?
AI-generated content may be incorrect
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,62 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import CopilotStudioAgent, CopilotStudioAgentThread
from semantic_kernel.contents import ChatMessageContent
from semantic_kernel.functions import KernelArguments
from semantic_kernel.prompt_template import PromptTemplateConfig
"""
This sample demonstrates how to use the Copilot Studio agent to answer questions from the user.
It demonstrates how to use a thread to maintain context between user inputs.
It also demonstrates how to use a custom prompt template.
"""
async def main() -> None:
# 1. Create the agent
agent = CopilotStudioAgent(
name="JokeAgent",
instructions="You are a joker. Tell kid-friendly jokes.",
prompt_template_config=PromptTemplateConfig(template="Craft jokes about {{$topic}}"),
)
# 2. Create a list of user inputs
USER_INPUTS = [ChatMessageContent(role="user", content="Tell me a joke to make me laugh.")]
# 3. Create a thread to maintain context between user inputs
thread: CopilotStudioAgentThread | None = None
# 4. Loop through the user inputs and get responses from the agent
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
response = await agent.get_response(
messages=user_input, thread=thread, arguments=KernelArguments(topic="pirate")
)
print(f"# {response.name}: {response}")
thread = response.thread
# 5. If a thread was created, delete it when done
if thread:
await thread.delete()
"""
# User: Tell me a joke to make me laugh.
# JokeAgent: Sure, here are a few pirate jokes for you:
1. Why don't pirates shower before they walk the plank?
Because they'll just wash up on shore later!
2. How do pirates prefer to communicate?
Aye to aye!
3. What's a pirate's favorite letter?
You might think it's "R," but their true love is the "C"!
Hope these made you smile!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,52 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import CopilotStudioAgent, CopilotStudioAgentThread
"""
This sample demonstrates how to use the Copilot Studio agent to perform a web search.
In Copilot Studio, for the specified agent, you must enable the "Web Search" capability.
If not already enabled, make sure to (re-)publish the agent so the changes take effect.
"""
async def main() -> None:
# 1. Create the agent
agent = CopilotStudioAgent(
name="WebSearchAgent",
instructions="Help answer the user's questions by searching the web.",
)
# 2. Create a list of user inputs
USER_INPUTS = [
"Which team won the 2025 NCAA Basketball championship?",
]
# 3. Create a thread to maintain context between user inputs
thread: CopilotStudioAgentThread | None = None
# 4. Loop through the user inputs and get responses from the agent
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
async for response in agent.invoke(messages=user_input, thread=thread):
print(f"# {response.name}: {response}")
thread = response.thread
# 5. If a thread was created, delete it when done
if thread:
await thread.delete()
"""
Sample output:
# User: Which team won the 2025 NCAA Basketball championship?
# WebSearchAgent: The Florida Gators won the 2025 NCAA Basketball championship by defeating the Houston Cougars
with a score of 65-63 [1].
[1]: https://www.ncaa.com/news/basketball-men/mml-official-bracket/2025-04-06/latest-bracket-schedule-and-scores-2025-ncaa-mens-tournament
"Latest bracket, schedule and scores for the 2025 NCAA men's tournament"
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,33 @@
# Multi-agent orchestration
The Semantic Kernel Agent Framework now supports orchestrating multiple agents to work together to complete a task.
## Background
The following samples are beneficial if you are just getting started with Semantic Kernel.
- [Chat Completion](../../concepts/chat_completion/)
- [Auto Function Calling](../../concepts/auto_function_calling/)
- [Structured Output](../../concepts/structured_output/)
- [Getting Started with Agents](../../getting_started_with_agents/)
- [More advanced agent samples](../../concepts/agents/)
## Prerequisites
The following environment variables are required to run the samples:
- OPENAI_API_KEY
- OPENAI_CHAT_MODEL_ID
However, if you are using other model services, feel free to switch to those in the samples.
Refer to [here](../../concepts/setup/README.md) on how to set up the environment variables for your model service.
## Orchestrations
| **Orchestrations** | **Description** |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Concurrent** | Useful for tasks that will benefit from independent analysis from multiple agents. |
| **Sequential** | Useful for tasks that require a well-defined step-by-step approach. |
| **Handoff** | Useful for tasks that are dynamic in nature and don't have a well-defined step-by-step approach. |
| **GroupChat** | Useful for tasks that will benefit from inputs from multiple agents and a highly configurable conversation flow. |
| **Magentic** | GroupChat like with a planner based manager. Inspired by [Magentic One](https://www.microsoft.com/en-us/research/articles/magentic-one-a-generalist-multi-agent-system-for-solving-complex-tasks/). |
@@ -0,0 +1,94 @@
# Copyright (c) Microsoft. All rights reserved.
import logging
import os
from azure.monitor.opentelemetry.exporter import AzureMonitorLogExporter, AzureMonitorTraceExporter
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.semconv.resource import ResourceAttributes
from opentelemetry.trace import set_tracer_provider
from opentelemetry.trace.span import format_trace_id
load_dotenv()
APPINSIGHTS_CONNECTION_STRING = os.getenv("APPINSIGHTS_CONNECTION_STRING")
resource = Resource.create({ResourceAttributes.SERVICE_NAME: "multi_agent_orchestration_sample"})
def set_up_logging():
class KernelFilter(logging.Filter):
"""A filter to not process records from semantic_kernel."""
# These are the namespaces that we want to exclude from logging for the purposes of this demo.
namespaces_to_exclude: list[str] = [
"semantic_kernel.functions.kernel_plugin",
"semantic_kernel.prompt_template.kernel_prompt_template",
]
def filter(self, record):
return not any([record.name.startswith(namespace) for namespace in self.namespaces_to_exclude])
exporters = []
exporters.append(AzureMonitorLogExporter(connection_string=APPINSIGHTS_CONNECTION_STRING))
# Create and set a global logger provider for the application.
logger_provider = LoggerProvider(resource=resource)
# Log processors are initialized with an exporter which is responsible
# for sending the telemetry data to a particular backend.
for log_exporter in exporters:
logger_provider.add_log_record_processor(BatchLogRecordProcessor(log_exporter))
# Sets the global default logger provider
set_logger_provider(logger_provider)
# Create a logging handler to write logging records, in OTLP format, to the exporter.
handler = LoggingHandler()
# Add filters to the handler to only process records from semantic_kernel.
handler.addFilter(logging.Filter("semantic_kernel"))
handler.addFilter(KernelFilter())
# Attach the handler to the root logger. `getLogger()` with no arguments returns the root logger.
# Events from all child loggers will be processed by this handler.
logger = logging.getLogger()
logger.addHandler(handler)
# Set the logging level to NOTSET to allow all records to be processed by the handler.
logger.setLevel(logging.NOTSET)
def set_up_tracing():
exporters = []
exporters.append(AzureMonitorTraceExporter(connection_string=APPINSIGHTS_CONNECTION_STRING))
# Initialize a trace provider for the application. This is a factory for creating tracers.
tracer_provider = TracerProvider(resource=resource)
# Span processors are initialized with an exporter which is responsible
# for sending the telemetry data to a particular backend.
for exporter in exporters:
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
# Sets the global default tracer provider
set_tracer_provider(tracer_provider)
def enable_observability(func):
"""A decorator to enable observability for the samples."""
async def wrapper(*args, **kwargs):
if not APPINSIGHTS_CONNECTION_STRING:
# If the connection string is not set, skip observability setup.
return await func(*args, **kwargs)
set_up_logging()
set_up_tracing()
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("main") as current_span:
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
return await func(*args, **kwargs)
return wrapper
@@ -0,0 +1,111 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, ConcurrentOrchestration
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to create a concurrent orchestration for
executing multiple agents on the same task in parallel.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a concurrent orchestration with multiple agents, invoking the orchestration, and finally
waiting for the results.
"""
def get_agents() -> list[Agent]:
"""Return a list of agents that will participate in the concurrent orchestration.
Feel free to add or remove agents.
"""
credential = AzureCliCredential()
physics_agent = ChatCompletionAgent(
name="PhysicsExpert",
instructions="You are an expert in physics. You answer questions from a physics perspective.",
service=AzureChatCompletion(credential=credential),
)
chemistry_agent = ChatCompletionAgent(
name="ChemistryExpert",
instructions="You are an expert in chemistry. You answer questions from a chemistry perspective.",
service=AzureChatCompletion(credential=credential),
)
return [physics_agent, chemistry_agent]
async def main():
"""Main function to run the agents."""
# 1. Create a concurrent orchestration with multiple agents
agents = get_agents()
concurrent_orchestration = ConcurrentOrchestration(members=agents)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await concurrent_orchestration.invoke(
task="What is temperature?",
runtime=runtime,
)
# 4. Wait for the results
# Note: the order of the results is not guaranteed to be the same
# as the order of the agents in the orchestration.
value = await orchestration_result.get(timeout=20)
for item in value:
print(f"# {item.name}: {item.content}")
# 5. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
"""
Sample output:
# PhysicsExpert: Temperature is a physical quantity that represents the average kinetic energy of the particles in
a substance. It is an indicator of how hot or cold an object is and determines the direction of heat transfer
between two objects. Heat flows from a region of higher temperature to a region of lower temperature until
thermal equilibrium is reached.
In terms of molecular dynamics, at higher temperatures, particles move more vigorously and have higher kinetic
energy, whereas at lower temperatures, their motion is less energetic. Temperature scales such as Celsius,
Fahrenheit, and Kelvin are used to quantify temperature. The Kelvin scale is particularly important in
scientific contexts because it starts at absolute zero—the theoretical point where particle motion would cease
completely.
Temperature also affects various physical properties of materials, such as their state (solid, liquid, or gas),
density, viscosity, and electrical conductivity. It is a crucial parameter in many areas of physics, from
thermodynamics to statistical mechanics and beyond.
# ChemistryExpert: Temperature is a fundamental concept in chemistry and physics, representing a measure of the
average kinetic energy of the particles in a substance. It reflects how hot or cold an object is and determines
the direction of heat transfer between substances. In more specific terms:
1. **Kinetic Energy Perspective:** At the molecular level, temperature is linked to the motions of the particles
comprising a substance. The greater the motion (translational, rotational, vibrational), the higher the
temperature. For example, in gases, temperature is directly related to the average kinetic energy of the gas
particles.
2. **Thermodynamic View:** Temperature is an intensive property and a state function, meaning it doesn't depend
on the amount of substance present. It is a critical parameter in the laws of thermodynamics, especially in
determining the spontaneity of processes and the distribution of energy in a system.
3. **Scales:** Temperature is measured using various scales, including Celsius (°C), Fahrenheit (°F), and
Kelvin (K). The Kelvin scale is the SI unit for temperature and starts at absolute zero (0 K), the theoretical
point where all molecular motion ceases.
4. **Effect on Chemical Reactions:** Temperature affects reaction rates, equilibrium positions, and the
solubility of substances. Generally, increasing temperature speeds up chemical reactions due to increased
molecular collisions and energy overcoming activation barriers.
Understanding temperature is essential in predicting and explaining chemical behavior and interactions in
reactions, phases changes, and even biological processes.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,137 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential
from pydantic import BaseModel
from semantic_kernel.agents import Agent, ChatCompletionAgent, ConcurrentOrchestration
from semantic_kernel.agents.orchestration.tools import structured_outputs_transform
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to create a concurrent orchestration for
executing multiple agents on the same task in parallel and returning a structured output.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a concurrent orchestration with multiple agents with a structure output transform,
invoking the orchestration, and finally waiting for the results.
"""
class ArticleAnalysis(BaseModel):
"""A model to hold the analysis of an article."""
themes: list[str]
sentiments: list[str]
entities: list[str]
def get_agents(credential: TokenCredential) -> list[Agent]:
"""Return a list of agents that will participate in the concurrent orchestration.
Feel free to add or remove agents.
"""
theme_agent = ChatCompletionAgent(
name="ThemeAgent",
instructions="You are an expert in identifying themes in articles. Given an article, identify the main themes.",
service=AzureChatCompletion(credential=credential),
)
sentiment_agent = ChatCompletionAgent(
name="SentimentAgent",
instructions="You are an expert in sentiment analysis. Given an article, identify the sentiment.",
service=AzureChatCompletion(credential=credential),
)
entity_agent = ChatCompletionAgent(
name="EntityAgent",
instructions="You are an expert in entity recognition. Given an article, extract the entities.",
service=AzureChatCompletion(credential=credential),
)
return [theme_agent, sentiment_agent, entity_agent]
async def main():
"""Main function to run the agents."""
# 1. Create a concurrent orchestration with multiple agents
# and a structure output transform.
# To enable structured output, you must specify the output transform
# and the generic types for the orchestration.
# Note: the chat completion service and model provided to the
# structure output transform must support structured output.
credential = AzureCliCredential()
agents = get_agents(credential)
concurrent_orchestration = ConcurrentOrchestration[str, ArticleAnalysis](
members=agents,
output_transform=structured_outputs_transform(ArticleAnalysis, AzureChatCompletion(credential=credential)),
)
# 2. Read the task from a file
with open(os.path.join(os.path.dirname(__file__), "../resources", "Hamlet_full_play_summary.txt")) as file:
task = file.read()
# 3. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 4. Invoke the orchestration with a task and the runtime
orchestration_result = await concurrent_orchestration.invoke(
task=task,
runtime=runtime,
)
# 5. Wait for the results
value = await orchestration_result.get(timeout=20)
if isinstance(value, ArticleAnalysis):
print(value.model_dump_json(indent=2))
else:
print("Unexpected result type:", type(value))
# 6. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
"""
Sample output:
{
"themes": [
"Revenge and Justice",
"Madness",
"Corruption and Power",
"Death and Mortality",
"Appearance vs. Reality",
"Family and Loyalty"
],
"sentiments": [
"dark",
"somber",
"negative"
],
"entities": [
"Elsinore Castle",
"Denmark",
"Horatio",
"King Hamlet",
"Claudius",
"Queen Gertrude",
"Prince Hamlet",
"Rosencrantz",
"Guildenstern",
"Polonius",
"Ophelia",
"Laertes",
"England",
"King of England",
"France",
"Osric",
"Fortinbras",
"Poland"
]
}
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,137 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, SequentialOrchestration
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatMessageContent
"""
The following sample demonstrates how to create a sequential orchestration for
executing multiple agents in sequence, i.e. the output of one agent is the input
to the next agent.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a sequential orchestration, invoking the orchestration, and finally waiting for the
results.
"""
def get_agents() -> list[Agent]:
"""Return a list of agents that will participate in the sequential orchestration.
Feel free to add or remove agents.
"""
credential = AzureCliCredential()
concept_extractor_agent = ChatCompletionAgent(
name="ConceptExtractorAgent",
instructions=(
"You are a marketing analyst. Given a product description, identify:\n"
"- Key features\n"
"- Target audience\n"
"- Unique selling points\n\n"
),
service=AzureChatCompletion(credential=credential),
)
writer_agent = ChatCompletionAgent(
name="WriterAgent",
instructions=(
"You are a marketing copywriter. Given a block of text describing features, audience, and USPs, "
"compose a compelling marketing copy (like a newsletter section) that highlights these points. "
"Output should be short (around 150 words), output just the copy as a single text block."
),
service=AzureChatCompletion(credential=credential),
)
format_proof_agent = ChatCompletionAgent(
name="FormatProofAgent",
instructions=(
"You are an editor. Given the draft copy, correct grammar, improve clarity, ensure consistent tone, "
"give format and make it polished. Output the final improved copy as a single text block."
),
service=AzureChatCompletion(credential=credential),
)
# The order of the agents in the list will be the order in which they are executed
return [concept_extractor_agent, writer_agent, format_proof_agent]
def agent_response_callback(message: ChatMessageContent) -> None:
"""Observer function to print the messages from the agents."""
print(f"# {message.name}\n{message.content}")
async def main():
"""Main function to run the agents."""
# 1. Create a sequential orchestration with multiple agents and an agent
# response callback to observe the output from each agent.
agents = get_agents()
sequential_orchestration = SequentialOrchestration(
members=agents,
agent_response_callback=agent_response_callback,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await sequential_orchestration.invoke(
task="An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get(timeout=20)
print(f"***** Final Result *****\n{value}")
# 5. Stop the runtime when idle
await runtime.stop_when_idle()
"""
Sample output:
# ConceptExtractorAgent
- Key Features:
- Made of eco-friendly stainless steel
- Keeps drinks cold for 24 hours
- Target Audience:
- Environmentally conscious consumers
- People who need a reliable way to keep their drinks cold for extended periods, such as athletes, travelers, and
outdoor enthusiasts
- Unique Selling Points:
- Environmentally sustainable material
- Exceptionally long-lasting cold temperature retention (24 hours)
# WriterAgent
Keep your beverages refreshingly chilled all day long with our eco-friendly stainless steel bottles. Perfect for
those who care about the planet, our bottles not only reduce waste but also promise to keep your drinks cold for
an impressive 24 hours. Whether you're an athlete pushing your limits, a traveler on the go, or simply an outdoor
enthusiast enjoying nature's beauty, this is the accessory you can't do without. Built from sustainable materials,
our bottles ensure both environmental responsibility and remarkable performance. Stay refreshed, stay green, and
make every sip a testament to your planet-friendly lifestyle. Join us in the journey towards a cooler, sustainable
tomorrow.
# FormatProofAgent
Keep your beverages refreshingly chilled all day long with our eco-friendly stainless steel bottles. Perfect for
those who care about the planet, our bottles not only reduce waste but also promise to keep your drinks cold for
an impressive 24 hours. Whether you're an athlete pushing your limits, a traveler on the go, or simply an outdoor
enthusiast enjoying nature's beauty, this is the accessory you can't do without. Built from sustainable materials,
our bottles ensure both environmental responsibility and remarkable performance. Stay refreshed, stay green, and
make every sip a testament to your planet-friendly lifestyle. Join us in the journey towards a cooler, sustainable
tomorrow.
***** Final Result *****
Keep your beverages refreshingly chilled all day long with our eco-friendly stainless steel bottles. Perfect for
those who care about the planet, our bottles not only reduce waste but also promise to keep your drinks cold for
an impressive 24 hours. Whether you're an athlete pushing your limits, a traveler on the go, or simply an outdoor
enthusiast enjoying nature's beauty, this is the accessory you can't do without. Built from sustainable materials,
our bottles ensure both environmental responsibility and remarkable performance. Stay refreshed, stay green, and
make every sip a testament to your planet-friendly lifestyle. Join us in the journey towards a cooler, sustainable
tomorrow.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,113 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import logging
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, SequentialOrchestration
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
"""
The following sample demonstrates how to cancel an invocation of an orchestration
that is still running.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a sequential orchestration, invoking the orchestration, and cancelling it before it
finishes.
"""
# Set up logging to see the invocation process
logging.basicConfig(level=logging.WARNING) # Set default level to WARNING
logging.getLogger("semantic_kernel.agents.orchestration.sequential").setLevel(logging.DEBUG)
def get_agents() -> list[Agent]:
"""Return a list of agents that will participate in the sequential orchestration.
Feel free to add or remove agents.
"""
credential = AzureCliCredential()
concept_extractor_agent = ChatCompletionAgent(
name="ConceptExtractorAgent",
instructions=(
"You are a marketing analyst. Given a product description, identify:\n"
"- Key features\n"
"- Target audience\n"
"- Unique selling points\n\n"
),
service=AzureChatCompletion(credential=credential),
)
writer_agent = ChatCompletionAgent(
name="WriterAgent",
instructions=(
"You are a marketing copywriter. Given a block of text describing features, audience, and USPs, "
"compose a compelling marketing copy (like a newsletter section) that highlights these points. "
"Output should be short (around 150 words), output just the copy as a single text block."
),
service=AzureChatCompletion(credential=credential),
)
format_proof_agent = ChatCompletionAgent(
name="FormatProofAgent",
instructions=(
"You are an editor. Given the draft copy, correct grammar, improve clarity, ensure consistent tone, "
"give format and make it polished. Output the final improved copy as a single text block."
),
service=AzureChatCompletion(credential=credential),
)
# The order of the agents in the list will be the order in which they are executed
return [concept_extractor_agent, writer_agent, format_proof_agent]
async def main():
"""Main function to run the agents."""
# 1. Create a sequential orchestration with multiple agents
agents = get_agents()
sequential_orchestration = SequentialOrchestration(members=agents)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await sequential_orchestration.invoke(
task="An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours",
runtime=runtime,
)
# 4. Cancel the orchestration before it finishes
await asyncio.sleep(1) # Simulate some delay before cancellation
orchestration_result.cancel()
try:
# Attempt to get the result will result in an exception due to cancellation
_ = await orchestration_result.get(timeout=20)
except Exception as e:
print(e)
finally:
# 5. Stop the runtime
await runtime.stop_when_idle()
"""
Sample output:
DEBUG:semantic_kernel.agents.orchestration.sequential:Registered agent actor of type
FormatProofAgent_5efa69d39306414c91325ef82145ec19
DEBUG:semantic_kernel.agents.orchestration.sequential:Registered agent actor of type
WriterAgent_5efa69d39306414c91325ef82145ec19
DEBUG:semantic_kernel.agents.orchestration.sequential:Registered agent actor of type
ConceptExtractorAgent_5efa69d39306414c91325ef82145ec19
DEBUG:semantic_kernel.agents.orchestration.sequential:Sequential actor
(Actor ID: ConceptExtractorAgent_5efa69d39306414c91325ef82145ec19/default; Agent name: ConceptExtractorAgent)
started processing...
The invocation was canceled before it could complete.
DEBUG:semantic_kernel.agents.orchestration.sequential:Sequential actor
(Actor ID: ConceptExtractorAgent_5efa69d39306414c91325ef82145ec19/default; Agent name: ConceptExtractorAgent)
finished processing.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,163 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, SequentialOrchestration
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import StreamingChatMessageContent
"""
The following sample demonstrates how to create a sequential orchestration for
executing multiple agents in sequence, i.e. the output of one agent is the input
to the next agent.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a sequential orchestration, invoking the orchestration, and finally waiting for the
results.
"""
def get_agents() -> list[Agent]:
"""Return a list of agents that will participate in the sequential orchestration.
Feel free to add or remove agents.
"""
credential = AzureCliCredential()
concept_extractor_agent = ChatCompletionAgent(
name="ConceptExtractorAgent",
instructions=(
"You are a marketing analyst. Given a product description, identify:\n"
"- Key features\n"
"- Target audience\n"
"- Unique selling points\n\n"
),
service=AzureChatCompletion(credential=credential),
)
writer_agent = ChatCompletionAgent(
name="WriterAgent",
instructions=(
"You are a marketing copywriter. Given a block of text describing features, audience, and USPs, "
"compose a compelling marketing copy (like a newsletter section) that highlights these points. "
"Output should be short (around 150 words), output just the copy as a single text block."
),
service=AzureChatCompletion(credential=credential),
)
format_proof_agent = ChatCompletionAgent(
name="FormatProofAgent",
instructions=(
"You are an editor. Given the draft copy, correct grammar, improve clarity, ensure consistent tone, "
"give format and make it polished. Output the final improved copy as a single text block."
),
service=AzureChatCompletion(credential=credential),
)
# The order of the agents in the list will be the order in which they are executed
return [concept_extractor_agent, writer_agent, format_proof_agent]
# Flag to indicate if a new message is being received
is_new_message = True
def streaming_agent_response_callback(message: StreamingChatMessageContent, is_final: bool) -> None:
"""Observer function to print the messages from the agents.
Args:
message (StreamingChatMessageContent): The streaming message content from the agent.
is_final (bool): Indicates if this is the final part of the message.
"""
global is_new_message
if is_new_message:
print(f"# {message.name}")
is_new_message = False
print(message.content, end="", flush=True)
if is_final:
print()
is_new_message = True
async def main():
"""Main function to run the agents."""
# 1. Create a sequential orchestration with multiple agents and an agent
# response callback to observe the output from each agent as they stream
# their responses.
agents = get_agents()
sequential_orchestration = SequentialOrchestration(
members=agents,
streaming_agent_response_callback=streaming_agent_response_callback,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await sequential_orchestration.invoke(
task="An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get(timeout=20)
print(f"***** Final Result *****\n{value}")
# 5. Stop the runtime when idle
await runtime.stop_when_idle()
"""
Sample output:
# ConceptExtractorAgent
**Key Features:**
- Made from eco-friendly stainless steel
- Insulation technology that keeps drinks cold for up to 24 hours
- Reusable design, promoting sustainability
- Possible variations in sizes and colors
**Target Audience:**
- Environmentally conscious consumers
- Active individuals and outdoor enthusiasts
- Health-conscious individuals looking to stay hydrated
- Students and professionals looking for stylish and functional drinkware
**Unique Selling Points:**
- Combines eco-friendliness with high performance in temperature retention
- Durable and reusable, reducing reliance on single-use plastics
- Sleek design that appeals to modern aesthetics while being functional
- Supporting sustainability initiatives through responsible manufacturing practices
# WriterAgent
Sip sustainably with our eco-friendly stainless steel water bottles, designed for the conscious consumer who values
both performance and aesthetics. Our bottles feature advanced insulation technology that keeps your drinks icy cold
for up to 24 hours, making them perfect for outdoor adventures, gym sessions, or a busy day at the office. Choose
from various sizes and stunning colors to match your personal style while making a positive impact on the planet.
Each reusable bottle helps reduce single-use plastics, supporting a cleaner, greener world. Join the movement toward
sustainability without compromising on style or functionality. Stay hydrated, look great, and make a difference—get
your eco-friendly water bottle today!
# FormatProofAgent
Sip sustainably with our eco-friendly stainless steel water bottles, designed for the conscious consumer who values
both performance and aesthetics. Our bottles utilize advanced insulation technology to keep your beverages icy cold
for up to 24 hours, making them perfect for outdoor adventures, gym sessions, or a busy day at the office.
Choose from a variety of sizes and stunning colors to match your personal style while positively impacting the
planet. Each reusable bottle helps reduce single-use plastics, supporting a cleaner, greener world.
Join the movement towards sustainability without compromising on style or functionality. Stay hydrated, look great,
and make a difference—get your eco-friendly water bottle today!
***** Final Result *****
Sip sustainably with our eco-friendly stainless steel water bottles, designed for the conscious consumer who values
both performance and aesthetics. Our bottles utilize advanced insulation technology to keep your beverages icy cold
for up to 24 hours, making them perfect for outdoor adventures, gym sessions, or a busy day at the office.
Choose from a variety of sizes and stunning colors to match your personal style while positively impacting the
planet. Each reusable bottle helps reduce single-use plastics, supporting a cleaner, greener world.
Join the movement towards sustainability without compromising on style or functionality. Stay hydrated, look great,
and make a difference—get your eco-friendly water bottle today!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,120 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, GroupChatOrchestration, RoundRobinGroupChatManager
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatMessageContent
"""
The following sample demonstrates how to create a group chat orchestration with a default
round robin manager for controlling the flow of conversation in a round robin fashion.
Think of the group chat manager as a state machine, with the following possible states:
- Request for user message
- Termination, after which the manager will try to filter a result from the conversation
- Continuation, at which the manager will select the next agent to speak
This sample demonstrates the basic steps of creating and starting a runtime, creating
a group chat orchestration with a group chat manager, invoking the orchestration,
and finally waiting for the results.
There are two agents in this orchestration: a writer and a reviewer. They work iteratively
to refine a slogan for a new electric SUV.
"""
def get_agents() -> list[Agent]:
"""Return a list of agents that will participate in the group style discussion.
Feel free to add or remove agents.
"""
credential = AzureCliCredential()
writer = ChatCompletionAgent(
name="Writer",
description="A content writer.",
instructions=(
"You are an excellent content writer. You create new content and edit contents based on the feedback."
),
service=AzureChatCompletion(credential=credential),
)
reviewer = ChatCompletionAgent(
name="Reviewer",
description="A content reviewer.",
instructions=(
"You are an excellent content reviewer. You review the content and provide feedback to the writer."
),
service=AzureChatCompletion(credential=credential),
)
# The order of the agents in the list will be the order in which they will be picked by the round robin manager
return [writer, reviewer]
def agent_response_callback(message: ChatMessageContent) -> None:
"""Observer function to print the messages from the agents."""
print(f"**{message.name}**\n{message.content}")
async def main():
"""Main function to run the agents."""
# 1. Create a group chat orchestration with a round robin manager
agents = get_agents()
group_chat_orchestration = GroupChatOrchestration(
members=agents,
# max_rounds is odd, so that the writer gets the last round
manager=RoundRobinGroupChatManager(max_rounds=5),
agent_response_callback=agent_response_callback,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await group_chat_orchestration.invoke(
task="Create a slogan for a new electric SUV that is affordable and fun to drive.",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get()
print(f"***** Result *****\n{value}")
# 5. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
"""
Sample output:
**Writer**
"Drive Tomorrow: Affordable Adventure Starts Today!"
**Reviewer**
This slogan, "Drive Tomorrow: Affordable Adventure Starts Today!", effectively communicates the core attributes of
the new electric SUV being promoted: affordability, fun, and forward-thinking. Here's some feedback:
...
Overall, the slogan captures the essence of an innovative, enjoyable, and accessible vehicle. Great job!
**Writer**
"Embrace the Future: Your Affordable Electric Adventure Awaits!"
**Reviewer**
This revised slogan, "Embrace the Future: Your Affordable Electric Adventure Awaits!", further enhances the message
of the electric SUV. Here's an evaluation:
...
Overall, this version of the slogan effectively communicates the vehicle's benefits while maintaining a positive
and engaging tone. Keep up the good work!
**Writer**
"Feel the Charge: Adventure Meets Affordability in Your New Electric SUV!"
***** Result *****
"Feel the Charge: Adventure Meets Affordability in Your New Electric SUV!"
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,161 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import sys
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, GroupChatOrchestration
from semantic_kernel.agents.orchestration.group_chat import BooleanResult, RoundRobinGroupChatManager
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import AuthorRole, ChatHistory, ChatMessageContent
if sys.version_info >= (3, 12):
from typing import override # pragma: no cover
else:
from typing_extensions import override # pragma: no cover
"""
The following sample demonstrates how to create a group chat orchestration with human
in the loop. Human in the loop is achieved by overriding the default round robin manager
to allow user input after the reviewer agent's message.
Think of the group chat manager as a state machine, with the following possible states:
- Request for user message
- Termination, after which the manager will try to filter a result from the conversation
- Continuation, at which the manager will select the next agent to speak
This sample demonstrates the basic steps of customizing the group chat manager to enter
the user input state, creating a human response function to get user input, and providing
it to the group chat manager.
There are two agents in this orchestration: a writer and a reviewer. They work iteratively
to refine a slogan for a new electric SUV.
"""
def get_agents() -> list[Agent]:
"""Return a list of agents that will participate in the group style discussion.
Feel free to add or remove agents.
"""
credential = AzureCliCredential()
writer = ChatCompletionAgent(
name="Writer",
description="A content writer.",
instructions=(
"You are an excellent content writer. You create new content and edit contents based on the feedback."
),
service=AzureChatCompletion(credential=credential),
)
reviewer = ChatCompletionAgent(
name="Reviewer",
description="A content reviewer.",
instructions=(
"You are an excellent content reviewer. You review the content and provide feedback to the writer."
),
service=AzureChatCompletion(credential=credential),
)
# The order of the agents in the list will be the order in which they will be picked by the round robin manager
return [writer, reviewer]
class CustomRoundRobinGroupChatManager(RoundRobinGroupChatManager):
"""Custom round robin group chat manager to enable user input."""
@override
async def should_request_user_input(self, chat_history: ChatHistory) -> BooleanResult:
"""Override the default behavior to request user input after the reviewer's message.
The manager will check if input from human is needed after each agent message.
"""
if len(chat_history.messages) == 0:
return BooleanResult(
result=False,
reason="No agents have spoken yet.",
)
last_message = chat_history.messages[-1]
if last_message.name == "Reviewer":
return BooleanResult(
result=True,
reason="User input is needed after the reviewer's message.",
)
return BooleanResult(
result=False,
reason="User input is not needed if the last message is not from the reviewer.",
)
def agent_response_callback(message: ChatMessageContent) -> None:
"""Observer function to print the messages from the agents."""
print(f"**{message.name}**\n{message.content}")
async def human_response_function(chat_histoy: ChatHistory) -> ChatMessageContent:
"""Function to get user input."""
user_input = input("User: ")
return ChatMessageContent(role=AuthorRole.USER, content=user_input)
async def main():
"""Main function to run the agents."""
# 1. Create a group chat orchestration with a round robin manager
agents = get_agents()
group_chat_orchestration = GroupChatOrchestration(
members=agents,
# max_rounds is odd, so that the writer gets the last round
manager=CustomRoundRobinGroupChatManager(
max_rounds=5,
human_response_function=human_response_function,
),
agent_response_callback=agent_response_callback,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await group_chat_orchestration.invoke(
task="Create a slogan for a new electric SUV that is affordable and fun to drive.",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get()
print(f"***** Result *****\n{value}")
# 5. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
"""
**Writer**
"Electrify Your Journey: Affordable Adventure Awaits!"
**Reviewer**
Your slogan captures the essence of being both affordable and fun, which is great! However, you might want to ...
User: I'd like to also make it rhyme
**Writer**
Sure! Here are a few rhyming slogan options for your electric SUV:
1. "Zoom Through the Streets, Feel the Beats!"
2. "Charge and Drive, Feel the Jive!"
3. "Electrify Your Ride, Let Fun Be Your Guide!"
4. "Zoom in Style, Drive with a Smile!"
Let me know if you'd like more options or variations!
**Reviewer**
These rhyming slogans are creative and energetic! They effectively capture the fun aspect while promoting ...
User: Please continue with the reviewer's suggestions
**Writer**
Absolutely! Let's refine and expand on the reviewer's suggestions for a more polished and appealing set of rhym...
***** Result *****
Absolutely! Let's refine and expand on the reviewer's suggestions for a more polished and appealing set of rhym...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,383 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import sys
from azure.core.credentials import TokenCredential
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, GroupChatOrchestration
from semantic_kernel.agents.orchestration.group_chat import BooleanResult, GroupChatManager, MessageResult, StringResult
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
from semantic_kernel.contents import AuthorRole, ChatHistory, ChatMessageContent
from semantic_kernel.functions import KernelArguments
from semantic_kernel.kernel import Kernel
from semantic_kernel.prompt_template import KernelPromptTemplate, PromptTemplateConfig
if sys.version_info >= (3, 12):
from typing import override # pragma: no cover
else:
from typing_extensions import override # pragma: no cover
"""
The following sample demonstrates how to create a group chat orchestration with a
group chat manager that uses a chat completion service to control the flow of the
conversation.
This sample creates a group of agents that represent different perspectives and put
them in a group chat to discuss a topic. The group chat manager is responsible for
controlling the flow of the conversation, selecting the next agent to speak, and
filtering the results of the conversation, which is a summary of the discussion.
"""
def get_agents(credential: TokenCredential) -> list[Agent]:
"""Return a list of agents that will participate in the group style discussion.
Feel free to add or remove agents.
"""
farmer = ChatCompletionAgent(
name="Farmer",
description="A rural farmer from Southeast Asia.",
instructions=(
"You're a farmer from Southeast Asia. "
"Your life is deeply connected to land and family. "
"You value tradition and sustainability. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
developer = ChatCompletionAgent(
name="Developer",
description="An urban software developer from the United States.",
instructions=(
"You're a software developer from the United States. "
"Your life is fast-paced and technology-driven. "
"You value innovation, freedom, and work-life balance. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
teacher = ChatCompletionAgent(
name="Teacher",
description="A retired history teacher from Eastern Europe",
instructions=(
"You're a retired history teacher from Eastern Europe. "
"You bring historical and philosophical perspectives to discussions. "
"You value legacy, learning, and cultural continuity. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
activist = ChatCompletionAgent(
name="Activist",
description="A young activist from South America.",
instructions=(
"You're a young activist from South America. "
"You focus on social justice, environmental rights, and generational change. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
spiritual_leader = ChatCompletionAgent(
name="SpiritualLeader",
description="A spiritual leader from the Middle East.",
instructions=(
"You're a spiritual leader from the Middle East. "
"You provide insights grounded in religion, morality, and community service. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
artist = ChatCompletionAgent(
name="Artist",
description="An artist from Africa.",
instructions=(
"You're an artist from Africa. "
"You view life through creative expression, storytelling, and collective memory. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
immigrant = ChatCompletionAgent(
name="Immigrant",
description="An immigrant entrepreneur from Asia living in Canada.",
instructions=(
"You're an immigrant entrepreneur from Asia living in Canada. "
"You balance trandition with adaption. "
"You focus on family success, risk, and opportunity. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
doctor = ChatCompletionAgent(
name="Doctor",
description="A doctor from Scandinavia.",
instructions=(
"You're a doctor from Scandinavia. "
"Your perspective is shaped by public health, equity, and structured societal support. "
"You are in a debate. Feel free to challenge the other participants with respect."
),
service=AzureChatCompletion(credential=credential),
)
return [farmer, developer, teacher, activist, spiritual_leader, artist, immigrant, doctor]
class ChatCompletionGroupChatManager(GroupChatManager):
"""A simple chat completion base group chat manager.
This chat completion service requires a model that supports structured output.
"""
service: ChatCompletionClientBase
topic: str
termination_prompt: str = (
"You are mediator that guides a discussion on the topic of '{{$topic}}'. "
"You need to determine if the discussion has reached a conclusion. "
"If you would like to end the discussion, please respond with True. Otherwise, respond with False."
)
selection_prompt: str = (
"You are mediator that guides a discussion on the topic of '{{$topic}}'. "
"You need to select the next participant to speak. "
"Here are the names and descriptions of the participants: "
"{{$participants}}\n"
"Please respond with only the name of the participant you would like to select."
)
result_filter_prompt: str = (
"You are mediator that guides a discussion on the topic of '{{$topic}}'. "
"You have just concluded the discussion. "
"Please summarize the discussion and provide a closing statement."
)
def __init__(self, topic: str, service: ChatCompletionClientBase, **kwargs) -> None:
"""Initialize the group chat manager."""
super().__init__(topic=topic, service=service, **kwargs)
async def _render_prompt(self, prompt: str, arguments: KernelArguments) -> str:
"""Helper to render a prompt with arguments."""
prompt_template_config = PromptTemplateConfig(template=prompt)
prompt_template = KernelPromptTemplate(prompt_template_config=prompt_template_config)
return await prompt_template.render(Kernel(), arguments=arguments)
@override
async def should_request_user_input(self, chat_history: ChatHistory) -> BooleanResult:
"""Provide concrete implementation for determining if user input is needed.
The manager will check if input from human is needed after each agent message.
"""
return BooleanResult(
result=False,
reason="This group chat manager does not require user input.",
)
@override
async def should_terminate(self, chat_history: ChatHistory) -> BooleanResult:
"""Provide concrete implementation for determining if the discussion should end.
The manager will check if the conversation should be terminated after each agent message
or human input (if applicable).
"""
should_terminate = await super().should_terminate(chat_history)
if should_terminate.result:
return should_terminate
chat_history.messages.insert(
0,
ChatMessageContent(
role=AuthorRole.SYSTEM,
content=await self._render_prompt(
self.termination_prompt,
KernelArguments(topic=self.topic),
),
),
)
chat_history.add_message(
ChatMessageContent(role=AuthorRole.USER, content="Determine if the discussion should end."),
)
response = await self.service.get_chat_message_content(
chat_history,
settings=PromptExecutionSettings(response_format=BooleanResult),
)
termination_with_reason = BooleanResult.model_validate_json(response.content)
print("*********************")
print(f"Should terminate: {termination_with_reason.result}\nReason: {termination_with_reason.reason}.")
print("*********************")
return termination_with_reason
@override
async def select_next_agent(
self,
chat_history: ChatHistory,
participant_descriptions: dict[str, str],
) -> StringResult:
"""Provide concrete implementation for selecting the next agent to speak.
The manager will select the next agent to speak after each agent message
or human input (if applicable) if the conversation is not terminated.
"""
chat_history.messages.insert(
0,
ChatMessageContent(
role=AuthorRole.SYSTEM,
content=await self._render_prompt(
self.selection_prompt,
KernelArguments(
topic=self.topic,
participants="\n".join([f"{k}: {v}" for k, v in participant_descriptions.items()]),
),
),
),
)
chat_history.add_message(
ChatMessageContent(role=AuthorRole.USER, content="Now select the next participant to speak."),
)
response = await self.service.get_chat_message_content(
chat_history,
settings=PromptExecutionSettings(response_format=StringResult),
)
participant_name_with_reason = StringResult.model_validate_json(response.content)
print("*********************")
print(
f"Next participant: {participant_name_with_reason.result}\nReason: {participant_name_with_reason.reason}."
)
print("*********************")
if participant_name_with_reason.result in participant_descriptions:
return participant_name_with_reason
raise RuntimeError(f"Unknown participant selected: {response.content}.")
@override
async def filter_results(
self,
chat_history: ChatHistory,
) -> MessageResult:
"""Provide concrete implementation for filtering the results of the discussion.
The manager will filter the results of the conversation after the conversation is terminated.
"""
if not chat_history.messages:
raise RuntimeError("No messages in the chat history.")
chat_history.messages.insert(
0,
ChatMessageContent(
role=AuthorRole.SYSTEM,
content=await self._render_prompt(
self.result_filter_prompt,
KernelArguments(topic=self.topic),
),
),
)
chat_history.add_message(
ChatMessageContent(role=AuthorRole.USER, content="Please summarize the discussion."),
)
response = await self.service.get_chat_message_content(
chat_history,
settings=PromptExecutionSettings(response_format=StringResult),
)
string_with_reason = StringResult.model_validate_json(response.content)
return MessageResult(
result=ChatMessageContent(role=AuthorRole.ASSISTANT, content=string_with_reason.result),
reason=string_with_reason.reason,
)
def agent_response_callback(message: ChatMessageContent) -> None:
"""Callback function to retrieve agent responses."""
print(f"**{message.name}**\n{message.content}")
async def main():
"""Main function to run the agents."""
# 1. Create a group chat orchestration with the custom group chat manager
credential = AzureCliCredential()
agents = get_agents(credential)
group_chat_orchestration = GroupChatOrchestration(
members=agents,
manager=ChatCompletionGroupChatManager(
topic="What does a good life mean to you personally?",
service=AzureChatCompletion(credential=credential),
max_rounds=10,
),
agent_response_callback=agent_response_callback,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await group_chat_orchestration.invoke(
task="Please start the discussion.",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get()
print(value)
# 5. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
"""
Sample output:
*********************
Should terminate: False
Reason: The discussion on what a good life means personally has not begun, meaning participants have not yet...
*********************
*********************
Next participant: Farmer
Reason: The Farmer from Southeast Asia can provide a perspective that highlights the importance of a connection...
*********************
**Farmer**
Thank you for the opportunity to share my perspective. As a farmer from Southeast Asia, my life is intricately...
*********************
Should terminate: False
Reason: The discussion has just started and only one perspective has been shared. There is room for further...
*********************
*********************
Next participant: Developer
Reason: To provide a contrast between rural and urban perspectives on what constitutes a good life, following the...
*********************
**Developer**
Thank you for the opportunity to join the discussion. As a software developer living in a technology-driven...
*********************
Should terminate: False
Reason: The discussion has just started with perspectives from both a farmer and a developer regarding the...
*********************
*********************
Next participant: Teacher
Reason: The Teacher, with their extensive experience and historical perspective, can provide valuable insights...
*********************
**Teacher**
As a retired history teacher from Eastern Europe, I find it fascinating to explore how the threads of history,...
*********************
Should terminate: True
Reason: The participants, representing diverse perspectives—a farmer, a developer, and a teacher—have each shared...
*********************
Our discussion on what constitutes a good life revolved around key perspectives from a farmer, a developer, and a...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,223 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, HandoffOrchestration, OrchestrationHandoffs
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import AuthorRole, ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a handoff orchestration that represents
a customer support triage system. The orchestration consists of 4 agents, each specialized
in a different area of customer support: triage, refunds, order status, and order returns.
Depending on the customer's request, agents can hand off the conversation to the appropriate
agent.
Human in the loop is achieved via a callback function similar to the one used in group chat
orchestration. Except that in the handoff orchestration, all agents have access to the
human response function, whereas in the group chat orchestration, only the manager has access
to the human response function.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a handoff orchestration, invoking the orchestration, and finally waiting for the results.
"""
class OrderStatusPlugin:
@kernel_function
def check_order_status(self, order_id: str) -> str:
"""Check the status of an order."""
# Simulate checking the order status
return f"Order {order_id} is shipped and will arrive in 2-3 days."
class OrderRefundPlugin:
@kernel_function
def process_refund(self, order_id: str, reason: str) -> str:
"""Process a refund for an order."""
# Simulate processing a refund
print(f"Processing refund for order {order_id} due to: {reason}")
return f"Refund for order {order_id} has been processed successfully."
class OrderReturnPlugin:
@kernel_function
def process_return(self, order_id: str, reason: str) -> str:
"""Process a return for an order."""
# Simulate processing a return
print(f"Processing return for order {order_id} due to: {reason}")
return f"Return for order {order_id} has been processed successfully."
def get_agents() -> tuple[list[Agent], OrchestrationHandoffs]:
"""Return a list of agents that will participate in the Handoff orchestration and the handoff relationships.
Feel free to add or remove agents and handoff connections.
"""
credential = AzureCliCredential()
support_agent = ChatCompletionAgent(
name="TriageAgent",
description="A customer support agent that triages issues.",
instructions="Handle customer requests.",
service=AzureChatCompletion(credential=credential),
)
refund_agent = ChatCompletionAgent(
name="RefundAgent",
description="A customer support agent that handles refunds.",
instructions="Handle refund requests.",
service=AzureChatCompletion(credential=credential),
plugins=[OrderRefundPlugin()],
)
order_status_agent = ChatCompletionAgent(
name="OrderStatusAgent",
description="A customer support agent that checks order status.",
instructions="Handle order status requests.",
service=AzureChatCompletion(credential=credential),
plugins=[OrderStatusPlugin()],
)
order_return_agent = ChatCompletionAgent(
name="OrderReturnAgent",
description="A customer support agent that handles order returns.",
instructions="Handle order return requests.",
service=AzureChatCompletion(credential=credential),
plugins=[OrderReturnPlugin()],
)
# Define the handoff relationships between agents
handoffs = (
OrchestrationHandoffs()
.add_many(
source_agent=support_agent.name,
target_agents={
refund_agent.name: "Transfer to this agent if the issue is refund related",
order_status_agent.name: "Transfer to this agent if the issue is order status related",
order_return_agent.name: "Transfer to this agent if the issue is order return related",
},
)
.add(
source_agent=refund_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not refund related",
)
.add(
source_agent=order_status_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not order status related",
)
.add(
source_agent=order_return_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not order return related",
)
)
return [support_agent, refund_agent, order_status_agent, order_return_agent], handoffs
def agent_response_callback(message: ChatMessageContent) -> None:
"""Observer function to print the messages from the agents.
Please note that this function is called whenever the agent generates a response,
including the internal processing messages (such as tool calls) that are not visible
to other agents in the orchestration.
"""
print(f"{message.name}: {message.content}")
for item in message.items:
if isinstance(item, FunctionCallContent):
print(f"Calling '{item.name}' with arguments '{item.arguments}'")
if isinstance(item, FunctionResultContent):
print(f"Result from '{item.name}' is '{item.result}'")
def human_response_function() -> ChatMessageContent:
"""Observer function to print the messages from the agents."""
user_input = input("User: ")
return ChatMessageContent(role=AuthorRole.USER, content=user_input)
async def main():
"""Main function to run the agents."""
# 1. Create a handoff orchestration with multiple agents
agents, handoffs = get_agents()
handoff_orchestration = HandoffOrchestration(
members=agents,
handoffs=handoffs,
agent_response_callback=agent_response_callback,
human_response_function=human_response_function,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await handoff_orchestration.invoke(
task="Greet the customer who is reaching out for support.",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get()
print(value)
# 5. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
"""
Sample output:
TriageAgent: Hello! Thank you for reaching out for support. How can I assist you today?
User: I'd like to track the status of my order
TriageAgent:
Calling 'Handoff-transfer_to_OrderStatusAgent' with arguments '{}'
TriageAgent:
Result from 'Handoff-transfer_to_OrderStatusAgent' is 'None'
OrderStatusAgent: Could you please provide me with your order ID so I can check the status for you?
User: My order ID is 123
OrderStatusAgent:
Calling 'OrderStatusPlugin-check_order_status' with arguments '{"order_id":"123"}'
OrderStatusAgent:
Result from 'OrderStatusPlugin-check_order_status' is 'Order 123 is shipped and will arrive in 2-3 days.'
OrderStatusAgent: Your order with ID 123 has been shipped and is expected to arrive in 2-3 days. If you have any
more questions, feel free to ask!
User: I want to return another order of mine
OrderStatusAgent: I can help you with that. Could you please provide me with the order ID of the order you want
to return?
User: Order ID 321
OrderStatusAgent:
Calling 'Handoff-transfer_to_TriageAgent' with arguments '{}'
OrderStatusAgent:
Result from 'Handoff-transfer_to_TriageAgent' is 'None'
TriageAgent:
Calling 'Handoff-transfer_to_OrderReturnAgent' with arguments '{}'
TriageAgent:
Result from 'Handoff-transfer_to_OrderReturnAgent' is 'None'
OrderReturnAgent: Could you please provide me with the reason for the return for order ID 321?
User: Broken item
Processing return for order 321 due to: Broken item
OrderReturnAgent:
Calling 'OrderReturnPlugin-process_return' with arguments '{"order_id":"321","reason":"Broken item"}'
OrderReturnAgent:
Result from 'OrderReturnPlugin-process_return' is 'Return for order 321 has been processed successfully.'
OrderReturnAgent: The return for order ID 321 has been processed successfully due to a broken item. If you need
further assistance or have any other questions, feel free to let me know!
User: No, bye
Task is completed with summary: Processed the return request for order ID 321 due to a broken item.
OrderReturnAgent:
Calling 'Handoff-complete_task' with arguments '{"task_summary":"Processed the return request for order ID 321
due to a broken item."}'
OrderReturnAgent:
Result from 'Handoff-complete_task' is 'None'
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,202 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from enum import Enum
from azure.identity import AzureCliCredential
from pydantic import BaseModel
from semantic_kernel.agents import Agent, ChatCompletionAgent, HandoffOrchestration, OrchestrationHandoffs
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import AuthorRole, ChatMessageContent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a handoff orchestration that can triage
GitHub issues based on their content. The orchestration consists of 3 agents, each
specialized in a different area.
The input to the orchestration is not longer a string or a chat message, but a Pydantic
model (i.e. structured inputs). The model will get transformed into a chat message before
being passed to the agents. This allows the orchestration to become more flexible and
easier reusable.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a handoff orchestration, invoking the orchestration, and finally waiting for the results.
"""
class GitHubLabels(Enum):
"""Enum representing GitHub labels."""
PYTHON = "python"
DOTNET = ".NET"
BUG = "bug"
ENHANCEMENT = "enhancement"
QUESTION = "question"
VECTORSTORE = "vectorstore"
AGENT = "agent"
class GithubIssue(BaseModel):
"""Model representing a GitHub issue."""
id: str
title: str
body: str
labels: list[str] = []
class Plan(BaseModel):
"""Model representing a plan for resolving a GitHub issue."""
tasks: list[str]
class GithubPlugin:
"""Plugin for GitHub related operations."""
@kernel_function
async def add_labels(self, issue_id: str, labels: list[GitHubLabels]) -> None:
"""Add labels to a GitHub issue."""
await asyncio.sleep(1) # Simulate network delay
print(f"Adding labels {labels} to issue {issue_id}")
@kernel_function(description="Create a plan to resolve the issue.")
async def create_plan(self, issue_id: str, plan: Plan) -> None:
"""Create tasks for a GitHub issue."""
await asyncio.sleep(1) # Simulate network delay
print(f"Creating plan for issue {issue_id} with tasks:\n{plan.model_dump_json(indent=2)}")
def get_agents() -> tuple[list[Agent], OrchestrationHandoffs]:
"""Return a list of agents that will participate in the Handoff orchestration and the handoff relationships.
Feel free to add or remove agents and handoff connections.
"""
credential = AzureCliCredential()
triage_agent = ChatCompletionAgent(
name="TriageAgent",
description="An agent that triages GitHub issues",
instructions="Given a GitHub issue, triage it.",
service=AzureChatCompletion(credential=credential),
)
python_agent = ChatCompletionAgent(
name="PythonAgent",
description="An agent that handles Python related issues",
instructions="You are an agent that handles Python related GitHub issues.",
service=AzureChatCompletion(credential=credential),
plugins=[GithubPlugin()],
)
dotnet_agent = ChatCompletionAgent(
name="DotNetAgent",
description="An agent that handles .NET related issues",
instructions="You are an agent that handles .NET related GitHub issues.",
service=AzureChatCompletion(credential=credential),
plugins=[GithubPlugin()],
)
# Define the handoff relationships between agents
handoffs = {
triage_agent.name: {
python_agent.name: "Transfer to this agent if the issue is Python related",
dotnet_agent.name: "Transfer to this agent if the issue is .NET related",
},
}
return [triage_agent, python_agent, dotnet_agent], handoffs
GithubIssueSample = GithubIssue(
id="12345",
title=(
"Bug: SQLite Error 1: 'ambiguous column name:' when including VectorStoreRecordKey in "
"VectorSearchOptions.Filter"
),
body=(
"Describe the bug"
"When using column names marked as [VectorStoreRecordData(IsFilterable = true)] in "
"VectorSearchOptions.Filter, the query runs correctly."
"However, using the column name marked as [VectorStoreRecordKey] in VectorSearchOptions.Filter, the query "
"throws exception 'SQLite Error 1: ambiguous column name: StartUTC"
""
"To Reproduce"
"Add a filter for the column marked [VectorStoreRecordKey]. Since that same column exists in both the "
"vec_TestTable and TestTable, the data for both columns cannot be returned."
""
"Expected behavior"
"The query should explicitly list the vec_TestTable column names to retrieve and should omit the "
"[VectorStoreRecordKey] column since it will be included in the primary TestTable columns."
""
"Platform"
""
"Microsoft.SemanticKernel.Connectors.Sqlite v1.46.0-preview"
"Additional context"
"Normal DBContext logging shows only normal context queries. Queries run by VectorizedSearchAsync() don't "
"appear in those logs and I could not find a way to enable logging in semantic search so that I could "
"actually see the exact query that is failing. It would have been very useful to see the failing semantic "
"query."
),
labels=[],
)
# The default input transform will attempt to serialize an object into a string by using
# `json.dump()`. However, an object of a Pydantic model type cannot be directly serialize
# by `json.dump()`. Thus, we will need a custom transform.
def custom_input_transform(input_message: GithubIssue) -> ChatMessageContent:
return ChatMessageContent(role=AuthorRole.USER, content=input_message.model_dump_json())
async def main():
"""Main function to run the agents."""
# 1. Create a handoff orchestration with multiple agents
# and a custom input transform.
# To enable structured input, you must specify the input transform
# and the generic types for the orchestration,
agents, handoffs = get_agents()
handoff_orchestration = HandoffOrchestration[GithubIssue, ChatMessageContent](
members=agents,
handoffs=handoffs,
input_transform=custom_input_transform,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await handoff_orchestration.invoke(
task=GithubIssueSample,
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get(timeout=100)
print(value)
# 5. Stop the runtime when idle
await runtime.stop_when_idle()
"""
Sample output:
Adding labels [<GitHubLabels.BUG: 'bug'>, <GitHubLabels.DOTNET: '.NET'>, <GitHubLabels.VECTORSTORE: 'vectorstore'>]
to issue 12345
Creating plan for issue 12345 with tasks:
{
"tasks": [
"Investigate the issue to confirm the ambiguity in the SQL query when using VectorStoreRecordKey in filters.",
"Modify the query generation logic to explicitly list column names for vec_TestTable and prevent ambiguity.",
"Test the solution to ensure VectorStoreRecordKey can be used in filters without causing SQLite errors.",
"Update documentation to provide guidance on using VectorStoreRecordKey in filters to avoid similar issues.",
"Consider adding logging capability to track semantic search queries for easier debugging in the future."
]
}
Task is completed with summary: No handoff agent name provided and no human response function set. Ending task.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,240 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, HandoffOrchestration, OrchestrationHandoffs
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import (
AuthorRole,
ChatMessageContent,
FunctionCallContent,
FunctionResultContent,
StreamingChatMessageContent,
)
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create a handoff orchestration that represents
a customer support triage system. The orchestration consists of 4 agents, each specialized
in a different area of customer support: triage, refunds, order status, and order returns.
The orchestration is configured with a streaming agent response callback that prints the
messages from the agents as they are generated.
Depending on the customer's request, agents can hand off the conversation to the appropriate
agent.
Human in the loop is achieved via a callback function similar to the one used in group chat
orchestration. Except that in the handoff orchestration, all agents have access to the
human response function, whereas in the group chat orchestration, only the manager has access
to the human response function.
This sample demonstrates the basic steps of creating and starting a runtime, creating
a handoff orchestration, invoking the orchestration, and finally waiting for the results.
"""
class OrderStatusPlugin:
@kernel_function
def check_order_status(self, order_id: str) -> str:
"""Check the status of an order."""
# Simulate checking the order status
return f"Order {order_id} is shipped and will arrive in 2-3 days."
class OrderRefundPlugin:
@kernel_function
def process_refund(self, order_id: str, reason: str) -> str:
"""Process a refund for an order."""
# Simulate processing a refund
print(f"Processing refund for order {order_id} due to: {reason}")
return f"Refund for order {order_id} has been processed successfully."
class OrderReturnPlugin:
@kernel_function
def process_return(self, order_id: str, reason: str) -> str:
"""Process a return for an order."""
# Simulate processing a return
print(f"Processing return for order {order_id} due to: {reason}")
return f"Return for order {order_id} has been processed successfully."
def get_agents() -> tuple[list[Agent], OrchestrationHandoffs]:
"""Return a list of agents that will participate in the Handoff orchestration and the handoff relationships.
Feel free to add or remove agents and handoff connections.
"""
credential = AzureCliCredential()
support_agent = ChatCompletionAgent(
name="TriageAgent",
description="A customer support agent that triages issues.",
instructions="Handle customer requests.",
service=AzureChatCompletion(credential=credential),
)
refund_agent = ChatCompletionAgent(
name="RefundAgent",
description="A customer support agent that handles refunds.",
instructions="Handle refund requests.",
service=AzureChatCompletion(credential=credential),
plugins=[OrderRefundPlugin()],
)
order_status_agent = ChatCompletionAgent(
name="OrderStatusAgent",
description="A customer support agent that checks order status.",
instructions="Handle order status requests.",
service=AzureChatCompletion(credential=credential),
plugins=[OrderStatusPlugin()],
)
order_return_agent = ChatCompletionAgent(
name="OrderReturnAgent",
description="A customer support agent that handles order returns.",
instructions="Handle order return requests.",
service=AzureChatCompletion(credential=credential),
plugins=[OrderReturnPlugin()],
)
# Define the handoff relationships between agents
handoffs = (
OrchestrationHandoffs()
.add_many(
source_agent=support_agent.name,
target_agents={
refund_agent.name: "Transfer to this agent if the issue is refund related",
order_status_agent.name: "Transfer to this agent if the issue is order status related",
order_return_agent.name: "Transfer to this agent if the issue is order return related",
},
)
.add(
source_agent=refund_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not refund related",
)
.add(
source_agent=order_status_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not order status related",
)
.add(
source_agent=order_return_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not order return related",
)
)
return [support_agent, refund_agent, order_status_agent, order_return_agent], handoffs
# Flag to indicate if a new message is being received
is_new_message = True
def streaming_agent_response_callback(message: StreamingChatMessageContent, is_final: bool) -> None:
"""Observer function to print the messages from the agents.
Please note that this function is called whenever the agent generates a response,
including the internal processing messages (such as tool calls) that are not visible
to other agents in the orchestration.
In streaming mode, the FunctionCallContent and FunctionResultContent are provided as a
complete message.
Args:
message (StreamingChatMessageContent): The streaming message content from the agent.
is_final (bool): Indicates if this is the final part of the message.
"""
global is_new_message
if is_new_message:
print(f"{message.name}: ", end="", flush=True)
is_new_message = False
print(message.content, end="", flush=True)
for item in message.items:
if isinstance(item, FunctionCallContent):
print(f"Calling '{item.name}' with arguments '{item.arguments}'", end="", flush=True)
if isinstance(item, FunctionResultContent):
print(f"Result from '{item.name}' is '{item.result}'", end="", flush=True)
if is_final:
print()
is_new_message = True
def human_response_function() -> ChatMessageContent:
"""Observer function to print the messages from the agents."""
user_input = input("User: ")
return ChatMessageContent(role=AuthorRole.USER, content=user_input)
async def main():
"""Main function to run the agents."""
# 1. Create a handoff orchestration with multiple agents
agents, handoffs = get_agents()
handoff_orchestration = HandoffOrchestration(
members=agents,
handoffs=handoffs,
streaming_agent_response_callback=streaming_agent_response_callback,
human_response_function=human_response_function,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await handoff_orchestration.invoke(
task="Greet the customer who is reaching out for support.",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get()
print(value)
# 5. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
"""
Sample output:
TriageAgent: Hello! Thank you for reaching out for support. How can I assist you today?
User: I'd like to track the status of my order
TriageAgent: Calling 'Handoff-transfer_to_OrderStatusAgent' with arguments '{}'
TriageAgent: Result from 'Handoff-transfer_to_OrderStatusAgent' is 'None'
OrderStatusAgent: Could you please provide me with your order ID? This will help me check the status of your order.
User: My order ID is 123
OrderStatusAgent: Calling 'OrderStatusPlugin-check_order_status' with arguments '{"order_id":"123"}'
OrderStatusAgent: Result from 'OrderStatusPlugin-check_order_status' is 'Order 123 is shipped and will arrive in
2-3 days.'
OrderStatusAgent: Your order with ID 123 has been shipped and is expected to arrive in 2-3 days. If you have any
more questions, feel free to ask!
User: I want to return another order of mine
OrderStatusAgent: Calling 'Handoff-transfer_to_TriageAgent' with arguments '{}'
OrderStatusAgent: Result from 'Handoff-transfer_to_TriageAgent' is 'None'
TriageAgent: Calling 'Handoff-transfer_to_OrderReturnAgent' with arguments '{}'
TriageAgent: Result from 'Handoff-transfer_to_OrderReturnAgent' is 'None'
OrderReturnAgent: Could you please provide me with the order ID for the order you would like to return, as well
as the reason for the return?
User: Order ID 321
OrderReturnAgent: What is the reason for returning order ID 321?
User: Broken item
Processing return for order 321 due to: Broken item
OrderReturnAgent: Calling 'OrderReturnPlugin-process_return' with arguments '{"order_id":"321","reason":"Broken
item"}'
OrderReturnAgent: Result from 'OrderReturnPlugin-process_return' is 'Return for order 321 has been processed
successfully.'
OrderReturnAgent: Task is completed with summary: Processed return for order ID 321 due to a broken item.
Calling 'Handoff-complete_task' with arguments '{"task_summary":"Processed return for order ID 321 due to a
broken item."}'
OrderReturnAgent: Result from 'Handoff-complete_task' is 'None'
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,272 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.ai.projects.aio import AIProjectClient
from azure.identity import AzureCliCredential
from azure.identity.aio import AzureCliCredential as AsyncAzureCliCredential
from opentelemetry.trace import NoOpTracerProvider
from samples.getting_started_with_agents.multi_agent_orchestration.observability import enable_observability
from semantic_kernel.agents import (
Agent,
AzureAIAgent,
AzureAIAgentSettings,
AzureAssistantAgent,
ChatCompletionAgent,
HandoffOrchestration,
OrchestrationHandoffs,
)
from semantic_kernel.agents.open_ai.azure_responses_agent import AzureResponsesAgent
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion, AzureOpenAISettings
from semantic_kernel.contents import AuthorRole, ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.functions import kernel_function
"""
The following sample replicates sample "step4_handoff.py" but uses different agent types.
The following agent types are used:
- ChatCompletionAgent: A Chat Completion agent that is backed by an Azure OpenAI service.
- AzureAssistantAgent: An Azure Assistant agent that is backed by the Azure OpenAI Assistant API.
- AzureAIAgent: An Azure AI agent that is backed by the Azure AI Agent (a.k.a Foundry Agent) service.
- OpenAIResponsesAgent: An Azure Responses agent that is backed by the Azure OpenAI Responses API.
The Handoff orchestration doesn't support the following agent types:
- BedrockAgent
- CopilotStudioAgent
"""
azure_credential: AsyncAzureCliCredential | None = None
azure_ai_agent_client: AIProjectClient | None = None
async def init_azure_ai_agent_clients():
global azure_credential, azure_ai_agent_client
azure_credential = AsyncAzureCliCredential()
azure_ai_agent_client = AzureAIAgent.create_client(credential=azure_credential)
async def close_azure_ai_agent_clients():
global azure_credential, azure_ai_agent_client
if azure_credential:
await azure_credential.close()
if azure_ai_agent_client:
await azure_ai_agent_client.close()
class OrderStatusPlugin:
@kernel_function
def check_order_status(self, order_id: str) -> str:
"""Check the status of an order."""
# Simulate checking the order status
return f"Order {order_id} is shipped and will arrive in 2-3 days."
class OrderRefundPlugin:
@kernel_function
def process_refund(self, order_id: str, reason: str) -> str:
"""Process a refund for an order."""
# Simulate processing a refund
print(f"Processing refund for order {order_id} due to: {reason}")
return f"Refund for order {order_id} has been processed successfully."
class OrderReturnPlugin:
@kernel_function
def process_return(self, order_id: str, reason: str) -> str:
"""Process a return for an order."""
# Simulate processing a return
print(f"Processing return for order {order_id} due to: {reason}")
return f"Return for order {order_id} has been processed successfully."
async def get_agents() -> tuple[list[Agent], OrchestrationHandoffs]:
"""Return a list of agents that will participate in the Handoff orchestration and the handoff relationships.
Feel free to add or remove agents and handoff connections.
"""
credential = AzureCliCredential()
# A Chat Completion agent that is backed by an Azure OpenAI service
support_agent = ChatCompletionAgent(
name="TriageAgent",
description="A customer support agent that triages issues.",
instructions="Handle customer requests.",
service=AzureChatCompletion(credential=credential),
)
# An Azure Assistant agent that is backed by the Azure OpenAI Assistant API
azure_assistant_agent_client = AzureAssistantAgent.create_client(credential=credential)
azure_assistant_agent_definition = await azure_assistant_agent_client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
description="A customer support agent that handles refunds.",
instructions="Handle refund requests.",
name="RefundAgent",
)
refund_agent = AzureAssistantAgent(
client=azure_assistant_agent_client,
definition=azure_assistant_agent_definition,
plugins=[OrderRefundPlugin()],
)
# An Azure Responses agent that is backed by the Azure OpenAI Responses API
azure_responses_agent_client = AzureResponsesAgent.create_client(credential=credential)
order_status_agent = AzureResponsesAgent(
ai_model_id=AzureOpenAISettings().responses_deployment_name,
client=azure_responses_agent_client,
instructions="Handle order status requests.",
description="A customer support agent that checks order status.",
name="OrderStatusAgent",
plugins=[OrderStatusPlugin()],
)
# An Azure AI agent that is backed by the Azure AI Agent (a.k.a Foundry Agent) service
azure_ai_agent_definition = await azure_ai_agent_client.agents.create_agent(
model=AzureAIAgentSettings().model_deployment_name,
name="OrderReturnAgent",
instructions="Handle order return requests.",
description="A customer support agent that handles order returns.",
)
order_return_agent = AzureAIAgent(
client=azure_ai_agent_client,
definition=azure_ai_agent_definition,
plugins=[OrderReturnPlugin()],
)
# Define the handoff relationships between agents
handoffs = (
OrchestrationHandoffs()
.add_many(
source_agent=support_agent.name,
target_agents={
refund_agent.name: "Transfer to this agent if the issue is refund related",
order_status_agent.name: "Transfer to this agent if the issue is order status related",
order_return_agent.name: "Transfer to this agent if the issue is order return related",
},
)
.add(
source_agent=refund_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not refund related",
)
.add(
source_agent=order_status_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not order status related",
)
.add(
source_agent=order_return_agent.name,
target_agent=support_agent.name,
description="Transfer to this agent if the issue is not order return related",
)
)
return [support_agent, refund_agent, order_status_agent, order_return_agent], handoffs
def agent_response_callback(message: ChatMessageContent) -> None:
"""Observer function to print the messages from the agents.
Please note that this function is called whenever the agent generates a response,
including the internal processing messages (such as tool calls) that are not visible
to other agents in the orchestration.
"""
print(f"{message.name}: {message.content}")
for item in message.items:
if isinstance(item, FunctionCallContent):
print(f"Calling '{item.name}' with arguments '{item.arguments}'")
if isinstance(item, FunctionResultContent):
print(f"Result from '{item.name}' is '{item.result}'")
def human_response_function() -> ChatMessageContent:
"""Observer function to print the messages from the agents."""
user_input = input("User: ")
return ChatMessageContent(role=AuthorRole.USER, content=user_input)
@enable_observability
async def main():
"""Main function to run the agents."""
# 0. Initialize the Azure AI agent clients
await init_azure_ai_agent_clients()
# 1. Create a handoff orchestration with multiple agents
agents, handoffs = await get_agents()
handoff_orchestration = HandoffOrchestration(
members=agents,
handoffs=handoffs,
agent_response_callback=agent_response_callback,
human_response_function=human_response_function,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime(tracer_provider=NoOpTracerProvider())
runtime.start()
try:
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await handoff_orchestration.invoke(
task="Greet the customer who is reaching out for support.",
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get()
print(value)
finally:
# 5. Stop the runtime after the invocation is complete
await runtime.stop_when_idle()
# 6. Clean up the resources
await close_azure_ai_agent_clients()
"""
Sample output:
TriageAgent: Hello! Thank you for reaching out for support. How can I assist you today?
User: I'd like to track the status of my order
TriageAgent:
Calling 'Handoff-transfer_to_OrderStatusAgent' with arguments '{}'
TriageAgent:
Result from 'Handoff-transfer_to_OrderStatusAgent' is 'None'
OrderStatusAgent: Could you please provide me with your order ID so I can check the status for you?
User: My order ID is 123
OrderStatusAgent:
Calling 'OrderStatusPlugin-check_order_status' with arguments '{"order_id":"123"}'
OrderStatusAgent:
Result from 'OrderStatusPlugin-check_order_status' is 'Order 123 is shipped and will arrive in 2-3 days.'
OrderStatusAgent: Your order with ID 123 has been shipped and is expected to arrive in 2-3 days. If you have any
more questions, feel free to ask!
User: I want to return another order of mine
OrderStatusAgent: I can help you with that. Could you please provide me with the order ID of the order you want
to return?
User: Order ID 321
OrderStatusAgent:
Calling 'Handoff-transfer_to_TriageAgent' with arguments '{}'
OrderStatusAgent:
Result from 'Handoff-transfer_to_TriageAgent' is 'None'
TriageAgent:
Calling 'Handoff-transfer_to_OrderReturnAgent' with arguments '{}'
TriageAgent:
Result from 'Handoff-transfer_to_OrderReturnAgent' is 'None'
OrderReturnAgent: Could you please provide me with the reason for the return for order ID 321?
User: Broken item
Processing return for order 321 due to: Broken item
OrderReturnAgent:
Calling 'OrderReturnPlugin-process_return' with arguments '{"order_id":"321","reason":"Broken item"}'
OrderReturnAgent:
Result from 'OrderReturnPlugin-process_return' is 'Return for order 321 has been processed successfully.'
OrderReturnAgent: The return for order ID 321 has been processed successfully due to a broken item. If you need
further assistance or have any other questions, feel free to let me know!
User: No, bye
Task is completed with summary: Processed the return request for order ID 321 due to a broken item.
OrderReturnAgent:
Calling 'Handoff-complete_task' with arguments '{"task_summary":"Processed the return request for order ID 321
due to a broken item."}'
OrderReturnAgent:
Result from 'Handoff-complete_task' is 'None'
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,199 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import (
Agent,
ChatCompletionAgent,
MagenticOrchestration,
OpenAIAssistantAgent,
StandardMagenticManager,
)
from semantic_kernel.agents.runtime import InProcessRuntime
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAISettings
from semantic_kernel.contents import ChatMessageContent
"""
The following sample demonstrates how to create a Magentic orchestration with two agents:
- A Research agent that can perform web searches
- A Coder agent that can run code using the code interpreter
Read more about Magentic here:
https://www.microsoft.com/en-us/research/articles/magentic-one-a-generalist-multi-agent-system-for-solving-complex-tasks/
This sample demonstrates the basic steps of creating and starting a runtime, creating
a Magentic orchestration with two agents and a Magentic manager, invoking the
orchestration, and finally waiting for the results.
The Magentic manager requires a chat completion model that supports structured output.
"""
async def agents() -> list[Agent]:
"""Return a list of agents that will participate in the Magentic orchestration.
Feel free to add or remove agents.
"""
research_agent = ChatCompletionAgent(
name="ResearchAgent",
description="A helpful assistant with access to web search. Ask it to perform web searches.",
instructions=(
"You are a Researcher. You find information without additional computation or quantitative analysis."
),
# This agent requires the gpt-4o-search-preview model to perform web searches.
# Feel free to explore with other agents that support web search, for example,
# the `OpenAIResponseAgent` or `AzureAIAgent` with bing grounding.
service=OpenAIChatCompletion(ai_model_id="gpt-4o-search-preview"),
)
# Create an OpenAI Assistant agent with code interpreter capability
client = OpenAIAssistantAgent.create_client()
code_interpreter_tool, code_interpreter_tool_resources = OpenAIAssistantAgent.configure_code_interpreter_tool()
definition = await client.beta.assistants.create(
model=OpenAISettings().chat_model_id,
name="CoderAgent",
description="A helpful assistant that writes and executes code to process and analyze data.",
instructions="You solve questions using code. Please provide detailed analysis and computation process.",
tools=code_interpreter_tool,
tool_resources=code_interpreter_tool_resources,
)
coder_agent = OpenAIAssistantAgent(
client=client,
definition=definition,
)
return [research_agent, coder_agent]
def agent_response_callback(message: ChatMessageContent) -> None:
"""Observer function to print the messages from the agents."""
print(f"**{message.name}**\n{message.content}")
async def main():
"""Main function to run the agents."""
# 1. Create a Magentic orchestration with two agents and a Magentic manager
# Note, the Standard Magentic manager uses prompts that have been tuned very
# carefully but it accepts custom prompts for advanced users and scenarios.
# For even more advanced scenarios, you can subclass the MagenticManagerBase
# and implement your own manager logic.
# The standard manager also requires a chat completion model that supports
# structured output.
magentic_orchestration = MagenticOrchestration(
members=await agents(),
manager=StandardMagenticManager(chat_completion_service=OpenAIChatCompletion()),
agent_response_callback=agent_response_callback,
)
# 2. Create a runtime and start it
runtime = InProcessRuntime()
runtime.start()
# 3. Invoke the orchestration with a task and the runtime
orchestration_result = await magentic_orchestration.invoke(
task=(
"I am preparing a report on the energy efficiency of different machine learning model architectures. "
"Compare the estimated training and inference energy consumption of ResNet-50, BERT-base, and GPT-2 "
"on standard datasets (e.g., ImageNet for ResNet, GLUE for BERT, WebText for GPT-2). "
"Then, estimate the CO2 emissions associated with each, assuming training on an Azure Standard_NC6s_v3 VM "
"for 24 hours. Provide tables for clarity, and recommend the most energy-efficient model "
"per task type (image classification, text classification, and text generation)."
),
runtime=runtime,
)
# 4. Wait for the results
value = await orchestration_result.get()
print(f"\nFinal result:\n{value}")
# 5. Stop the runtime when idle
await runtime.stop_when_idle()
"""
Sample output:
**ResearchAgent**
Estimating the energy consumption and associated CO₂ emissions for training and inference of ResNet-50, BERT-base...
**CoderAgent**
Here is the comparison of energy consumption and CO₂ emissions for each model (ResNet-50, BERT-base, and GPT-2)
over a 24-hour period:
| Model | Training Energy (kWh) | Inference Energy (kWh) | Total Energy (kWh) | CO₂ Emissions (kg) |
|-----------|------------------------|------------------------|---------------------|---------------------|
| ResNet-50 | 21.11 | 0.08232 | 21.19232 | 19.50 |
| BERT-base | 0.048 | 0.23736 | 0.28536 | 0.26 |
| GPT-2 | 42.22 | 0.35604 | 42.57604 | 39.17 |
### Recommendations:
...
**CoderAgent**
Here are the recalibrated results for energy consumption and CO₂ emissions, assuming a more conservative approach
for models like GPT-2:
| Model | Training Energy (kWh) | Inference Energy (kWh) | Total Energy (kWh) | CO₂ Emissions (kg) |
|------------------|------------------------|------------------------|---------------------|---------------------|
| ResNet-50 | 21.11 | 0.08232 | 21.19232 | 19.50 |
| BERT-base | 0.048 | 0.23736 | 0.28536 | 0.26 |
| GPT-2 (Adjusted) | 42.22 | 0.35604 | 42.57604 | 39.17 |
...
**ResearchAgent**
Estimating the energy consumption and associated CO₂ emissions for training and inference of machine learning ...
**ResearchAgent**
Estimating the energy consumption and CO₂ emissions of training and inference for ResNet-50, BERT-base, and ...
**CoderAgent**
Here is the estimated energy use and CO₂ emissions for a full day of operation for each model on an Azure ...
**ResearchAgent**
Recent analyses have highlighted the substantial energy consumption and carbon emissions associated with ...
**CoderAgent**
Here's the refined estimation for the energy use and CO₂ emissions for optimized models on an Azure ...
**CoderAgent**
To provide precise estimates for CO₂ emissions based on Azure's regional data centers' carbon intensity, we need ...
**ResearchAgent**
To refine the CO₂ emission estimates for training and inference of ResNet-50, BERT-base, and GPT-2 on an Azure ...
**CoderAgent**
Here's the refined comparative table for energy consumption and CO₂ emissions for ResNet-50, BERT-base, and GPT-2,
taking into account carbon intensity data for Azure's West Europe and Sweden Central regions:
| Model | Energy (kWh) | CO₂ Emissions West Europe (kg) | CO₂ Emissions Sweden Central (kg) |
|------------|--------------|--------------------------------|-----------------------------------|
| ResNet-50 | 5.76 | 0.639 | 0.086 |
| BERT-base | 9.18 | 1.019 | 0.138 |
| GPT-2 | 12.96 | 1.439 | 0.194 |
**Refined Recommendations:**
...
Final result:
Here is the comprehensive report on energy efficiency and CO₂ emissions for ResNet-50, BERT-base, and GPT-2 models
when trained and inferred on an Azure Standard_NC6s_v3 VM for 24 hours.
### Energy Consumption and CO₂ Emissions:
Based on refined analyses, here are the estimated energy consumption and CO₂ emissions for each model:
| Model | Energy (kWh) | CO₂ Emissions West Europe (kg) | CO₂ Emissions Sweden Central (kg) |
|------------|--------------|--------------------------------|-----------------------------------|
| ResNet-50 | 5.76 | 0.639 | 0.086 |
| BERT-base | 9.18 | 1.019 | 0.138 |
| GPT-2 | 12.96 | 1.439 | 0.194 |
### Recommendations for Energy Efficiency:
...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,110 @@
## OpenAI Assistant Agents
The following getting started samples show how to use OpenAI Assistant agents with Semantic Kernel.
## Assistants API Overview
The Assistants API is a robust solution from OpenAI that empowers developers to integrate powerful, purpose-built AI assistants into their applications. It streamlines the development process by handling conversation histories, managing threads, and providing seamless access to advanced tools.
### Key Features
- **Purpose-Built AI Assistants:**
Assistants are specialized AIs that leverage OpenAIs models to interact with users, access files, maintain persistent threads, and call additional tools. This enables highly tailored and effective user interactions.
- **Simplified Conversation Management:**
The concept of a **thread** -- a dedicated conversation session between an assistant and a user -- ensures that message history is managed automatically. Threads optimize the conversation context by storing and truncating messages as needed.
- **Integrated Tool Access:**
The API provides built-in tools such as:
- **Code Interpreter:** Allows the assistant to execute code, enhancing its ability to solve complex tasks.
- **File Search:** Implements best practices for retrieving data from uploaded files, including advanced chunking and embedding techniques.
- **Enhanced Function Calling:**
With improved support for third-party tool integration, the Assistants API enables assistants to extend their capabilities beyond native functions.
For more detailed technical information, refer to the [Assistants API](https://platform.openai.com/docs/assistants/overview).
### Semantic Kernel OpenAI Assistant Agents
OpenAI Assistant Agents are created in the following way:
```python
from semantic_kernel.agents import OpenAIAssistantAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
# Create the client using OpenAI resources and configuration
client = OpenAIAssistantAgent.create_client()
# Create the assistant definition
definition = await client.beta.assistants.create(
model=OpenAISettings().chat_model_id,
instructions="<instructions>",
name="<name>",
)
# Define the Semantic Kernel OpenAI Assistant Agent
agent = OpenAIAssistantAgent(
client=client,
definition=definition,
)
# Define a thread to hold the conversation's context
# If a thread is not created initially it will be created
# and returned as part of the first response
thread = None
# Get the agent response
response = await agent.get_response(messages="Why is the sky blue?", thread=thread)
thread = response.thread
# or use the agent.invoke(...) method
async for response in agent.invoke(messages="Why is the sky blue?", thread=thread):
print(f"# {response.role}: {response.content}")
thread = response.thread
```
### Semantic Kernel Azure Assistant Agents
Azure Assistant Agents are currently in preview and require a `-preview` API version (minimum version: `2024-05-01-preview`). As new features are introduced, API versions will be updated accordingly. For the latest versioning details, please refer to the [Azure OpenAI API preview lifecycle](https://learn.microsoft.com/azure/ai-services/openai/api-version-deprecation).
To specify the correct API version, set the following environment variable (for example, in your `.env` file):
```bash
AZURE_OPENAI_API_VERSION="2025-01-01-preview"
```
Alternatively, you can pass the `api_version` parameter when creating an `AzureAssistantAgent`:
```python
from semantic_kernel.agents import AzureAssistantAgent
# Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client()
# Create the assistant definition
definition = await client.beta.assistants.create(
model=model,
instructions="<instructions>",
name="<name>",
)
# Define the Semantic Kernel Azure OpenAI Assistant Agent
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# Define a thread to hold the conversation's context
# If a thread is not created initially it will be created
# and returned as part of the first response
thread = None
# Get the agent response
response = await agent.get_response(messages="Why is the sky blue?", thread=thread)
thread = response.thread
# or use the agent.invoke(...) method
async for response in agent.invoke(messages="Why is the sky blue?", thread=thread):
print(f"# {response.role}: {response.content}")
thread = response.thread
```
@@ -0,0 +1,76 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI assistant using either
Azure OpenAI or OpenAI. The sample shows how to have the assistant answrer
questions about the world.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Why is the sky blue?",
"What is the speed of light?",
"What have we been talking about?",
]
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# 2. Create the assistant on the Azure OpenAI service
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
instructions="Answer questions about the world in one sentence.",
name="Assistant",
)
# 3. Create a Semantic Kernel agent for the Azure OpenAI assistant
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# 4. Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 6. Invoke the agent for the current thread and print the response
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 7. Clean up the resources
await thread.delete() if thread else None
await agent.client.beta.assistants.delete(assistant_id=agent.id)
"""
You should see output similar to the following:
# User: 'Why is the sky blue?'
# Agent: The sky appears blue because molecules in the atmosphere scatter sunlight in all directions, and blue
light is scattered more than other colors because it travels in shorter, smaller waves.
# User: 'What is the speed of light?'
# Agent: The speed of light in a vacuum is approximately 299,792,458 meters per second
(about 186,282 miles per second).
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,100 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI. The sample
shows how to use a Semantic Kernel plugin as part of the
OpenAI Assistant.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"What is the special drink?",
"How much is it?",
"Thank you",
]
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# 2. Create the assistant on the Azure OpenAI service
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
instructions="Answer questions about the menu.",
name="Host",
)
# 3. Create a Semantic Kernel agent for the Azure OpenAI assistant
agent = AzureAssistantAgent(
client=client,
definition=definition,
plugins=[MenuPlugin()], # The plugins can be passed in as a list to the constructor
)
# Note: plugins can also be configured on the Kernel and passed in as a parameter to the OpenAIAssistantAgent
# 4. Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 6. Invoke the agent for the current thread and print the response
async for response in agent.invoke(messages=user_input, thread=thread):
print(f"# Agent: {response}")
thread = response.thread
finally:
# 7. Clean up the resources
await thread.delete() if thread else None
await agent.client.beta.assistants.delete(assistant_id=agent.id)
"""
You should see output similar to the following:
# User: 'Hello'
# Agent: Hello! How can I assist you today?
# User: 'What is the special soup?'
# Agent: The special soup today is Clam Chowder. Would you like to know more about any other menu items?
# User: 'What is the special drink?'
# Agent: The special drink today is Chai Tea. Would you like more information on anything else?
# User: 'Thank you'
# Agent: You're welcome! If you have any more questions or need further assistance, feel free to ask.
Enjoy your day!
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,89 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from semantic_kernel.agents import AssistantAgentThread, OpenAIAssistantAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
from semantic_kernel.contents import AuthorRole, ChatMessageContent, FileReferenceContent, ImageContent, TextContent
"""
The following sample demonstrates how to create an OpenAI
assistant using OpenAI configuration, and leverage the
multi-modal content types to have the assistant describe images
and answer questions about them. This sample uses non-streaming responses.
"""
async def main():
# 1. Create the OpenAI Assistant Agent client
# Note Azure OpenAI doesn't support vision files yet
client = OpenAIAssistantAgent.create_client()
# 2. Load a sample image of a cat used for the assistant to describe
file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "cat.jpg")
with open(file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
# 3. Create the assistant on the OpenAI service
definition = await client.beta.assistants.create(
model=OpenAISettings().chat_model_id,
instructions="Answer questions about the provided images.",
name="Vision",
)
# 4. Create a Semantic Kernel agent for the OpenAI assistant
agent = OpenAIAssistantAgent(
client=client,
definition=definition,
)
# 5. Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
# 6. Define the user messages with the image content to simulate the conversation
user_messages = {
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="Describe this image."),
ImageContent(
uri="https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/New_york_times_square-terabass.jpg/1200px-New_york_times_square-terabass.jpg"
),
],
),
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="What is the main color in this image?"),
ImageContent(uri="https://upload.wikimedia.org/wikipedia/commons/5/56/White_shark.jpg"),
],
),
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="Is there an animal in this image?"),
FileReferenceContent(file_id=file.id),
],
),
}
try:
for message in user_messages:
print(f"# User: {str(message)}") # type: ignore
# 8. Invoke the agent for the current thread and print the response
async for response in agent.invoke(messages=message, thread=thread):
print(f"# Agent: {response}\n")
thread = response.thread
finally:
# 9. Clean up the resources
await client.files.delete(file.id)
await thread.delete() if thread else None
await agent.client.beta.assistants.delete(assistant_id=agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,59 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI
assistant using either Azure OpenAI or OpenAI and leverage the
assistant's code interpreter functionality to have it write
Python code to print Fibonacci numbers.
"""
TASK = "Use code to determine the values in the Fibonacci sequence that that are less than the value of 101?"
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# 2. Configure the code interpreter tool and resources for the Assistant
code_interpreter_tool, code_interpreter_tool_resources = AzureAssistantAgent.configure_code_interpreter_tool()
# 3. Create the assistant on the Azure OpenAI service
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
name="CodeRunner",
instructions="Run the provided request as code and return the result.",
tools=code_interpreter_tool,
tool_resources=code_interpreter_tool_resources,
)
# 4. Create a Semantic Kernel agent for the Azure OpenAI assistant
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# 5. Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
print(f"# User: '{TASK}'")
try:
# 6. Invoke the agent for the current thread and print the response
async for response in agent.invoke(messages=TASK, thread=thread):
print(f"# Agent: {response}")
thread = response.thread
finally:
# 7. Clean up the resources
await thread.delete() if thread else None
await agent.client.beta.assistants.delete(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,81 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI
Assistant using either Azure OpenAI or OpenAI and leverage the
assistant's file search functionality.
"""
# Simulate a conversation with the agent
USER_INPUTS = {
"Who is the youngest employee?",
"Who works in sales?",
"I have a customer request, who can help me?",
}
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureAssistantAgent.create_client(credential=AzureCliCredential())
# 2. Read and upload the file to the Azure OpenAI assistant service
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "employees.pdf"
)
with open(pdf_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
vector_store = await client.vector_stores.create(
name="step4_assistant_file_search",
file_ids=[file.id],
)
# 3. Create file search tool with uploaded resources
file_search_tool, file_search_tool_resources = AzureAssistantAgent.configure_file_search_tool(vector_store.id)
# 4. Create the assistant on the Azure OpenAI service with the file search tool
definition = await client.beta.assistants.create(
model=AzureOpenAISettings().chat_deployment_name,
instructions="Find answers to the user's questions in the provided file.",
name="FileSearch",
tools=file_search_tool,
tool_resources=file_search_tool_resources,
)
# 5. Create a Semantic Kernel agent for the Azure OpenAI assistant
agent = AzureAssistantAgent(
client=client,
definition=definition,
)
# 6. Create a new thread for use with the assistant
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread: AssistantAgentThread = None
try:
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 7. Invoke the agent for the current thread and print the response
async for response in agent.invoke(messages=user_input, thread=thread):
print(f"# Agent: {response}")
thread = response.thread
finally:
# 9. Clean up the resources
await client.files.delete(file.id)
await client.vector_stores.delete(vector_store.id)
await client.beta.threads.delete(thread.id)
await client.beta.assistants.delete(agent.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,98 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from semantic_kernel.agents import AgentRegistry, OpenAIAssistantAgent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI Assistant agent that answers
questions about a sample menu using a Semantic Kernel Plugin. The agent is created
using a yaml declarative spec.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Define the YAML string for the sample
SPEC = """
type: openai_assistant
name: Host
instructions: Respond politely to the user's questions.
model:
id: ${OpenAI:ChatModelId}
tools:
- id: MenuPlugin.get_specials
type: function
- id: MenuPlugin.get_item_price
type: function
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = OpenAIAssistantAgent.create_client()
# 2. Create the assistant on the Azure OpenAI service
agent: OpenAIAssistantAgent = await AgentRegistry.create_from_yaml(
SPEC,
plugins=[MenuPlugin()],
client=client,
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 5. Clean up the resources
await thread.delete() if thread else None
await agent.client.beta.assistants.delete(assistant_id=agent.id)
"""
Sample Output:
# User: Hello
# Agent: Hello! How can I assist you today?
# User: What is the special soup?
# ...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,30 @@
## Semantic Kernel OpenAI Responses Agent
The responses API is OpenAI's latest core API and an agentic API primitive. See more details [here](https://platform.openai.com/docs/guides/responses-vs-chat-completions).
### OpenAI Responses Agent
In Semantic Kernel, we don't currently support the Computer User Agent Tool. This is coming soon.
#### Environment Variables / Config
`OPENAI_RESPONSES_MODEL_ID=""`
### Azure Responses Agent
The Semantic Kernel Azure Responses Agent leverages Azure OpenAI's new stateful API.
It brings together the best capabilities from the chat completions and assistants API in one unified experience.
For `AzureResponsesAgent` limitations, please see the latest [Azure OpenAI Responses API Docs](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/responses?tabs=python-secure).
#### API Support
`2025-03-01-preview` or later, therefore please use `AZURE_OPENAI_API_VERSION="2025-03-01-preview"`.
Please visit the following [link](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/responses?tabs=python-secure) to view region availability, model support, and further details.
#### Environment Variables / Config
`AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME=""`
The other Azure OpenAI config values used for AzureAssistantAgent or AzureChatCompletion, like `AZURE_OPENAI_API_VERSION` or `AZURE_OPENAI_ENDPOINT` are still valid for the `AzureResponsesAgent`.
@@ -0,0 +1,67 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AzureResponsesAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI Responses Agent using either
Azure OpenAI or OpenAI. The sample shows how to have the agent answer
questions about the world.
Note, in this sample, a thread is not used. This creates a stateless agent. It will
not be able to recall previous messages, which is expected behavior.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
USER_INPUTS = [
"Hi, my name is John Doe.",
"Why is the sky blue?",
"What is the speed of light?",
"What is my name?",
]
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = AzureResponsesAgent(
ai_model_id=AzureOpenAISettings().responses_deployment_name,
client=client,
instructions="Answer questions about the world in one sentence.",
name="Expert",
)
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 3. Invoke the agent for the current message and print the response
response = await agent.get_response(messages=user_input)
# We are not using a thread for context, so there will be no memory
print(f"# {response.name}: {response.content}")
"""
You should see output similar to the following:
# User: 'Hi, my name is John Doe.'
# Expert: Hello, John Doe! How can I assist you today?
# User: 'Why is the sky blue?'
# Expert: The sky appears blue because of Rayleigh scattering, where shorter blue light wavelengths are scattered
more than other colors by the gases in Earth's atmosphere.
# User: 'What is the speed of light?'
# Expert: The speed of light in a vacuum is approximately 299,792 kilometers per second (km/s).
# User: 'What is my name?'
# Expert: I'm sorry, I can't determine your name from our conversation.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,73 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AzureResponsesAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI Responses Agent.
The sample shows how to have the agent answer questions about the world.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
USER_INPUTS = [
"My name is John Doe.",
"Tell me a joke",
"Explain why this is funny.",
"What have we been talking about?",
]
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = AzureResponsesAgent(
ai_model_id=AzureOpenAISettings().responses_deployment_name,
client=client,
instructions="Answer questions about from the user.",
name="Joker",
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 4. Invoke the agent for the current message and print the response
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response.content}")
# 5. Update the thread so the previous response id is used
thread = response.thread
"""
You should see output similar to the following:
# User: 'My name is John Doe.'
# Joker: Hello, John! How can I assist you today?
# User: 'Tell me a joke'
# Joker: Sure! Why don't scientists trust atoms?
Because they make up everything!
# User: 'Explain why this is funny.'
# Joker: The joke is funny because it plays on the double meaning of "make up." In one sense, atoms are the
building blocks of all matter, so they literally "make up" everything. In another sense, "make up" can mean
to fabricate or lie, humorously suggesting that atoms are untrustworthy because they "invent" or "fabricate"
everything. This clever wordplay is what makes the joke amusing.
# User: 'What have we been talking about?'
# Joker: We've been discussing a joke about atoms and its humor, focusing on wordplay and double meanings.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,93 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AzureResponsesAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI Responses Agent.
The sample shows how to have the agent answer questions about the sample menu.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"What is the special drink?",
"How much is it?",
"Thank you",
]
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = AzureResponsesAgent(
ai_model_id=AzureOpenAISettings().responses_deployment_name,
client=client,
instructions="Answer questions about the menu.",
name="Host",
plugins=[MenuPlugin()],
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 4. Invoke the agent for the current message and print the response
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response.content}")
thread = response.thread
"""
You should see output similar to the following:
# User: 'Hello'
# Host: Hi there! How can I assist you today?
# User: 'What is the special soup?'
# Host: The special soup is Clam Chowder.
# User: 'What is the special drink?'
# Host: The special drink is Chai Tea.
# User: 'How much is it?'
# Host: The Chai Tea costs $9.99.
# User: 'Thank you'
# Host: You're welcome! If you have any more questions, feel free to ask.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,68 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
"""
The following sample demonstrates how to create an OpenAI Responses Agent.
The sample shows how to have the agent answer questions using the web search
preview tool with streaming responses.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Find me news articles about the latest technology trends.",
]
async def main():
# 1. Create the client using OpenAI resources and configuration
# Note: the Azure OpenAI Responses API does not yet support the web search tool.
client = OpenAIResponsesAgent.create_client()
web_search_tool = OpenAIResponsesAgent.configure_web_search_tool()
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = OpenAIResponsesAgent(
ai_model_id=OpenAISettings().responses_model_id,
client=client,
instructions="Answer questions from the user about performing web searches for news.",
name="NewsSearcher",
tools=[web_search_tool],
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# {response.name}: {response.content}")
thread = response.thread
"""
You should see output similar to the following:
# User: 'Find me news articles about the latest technology trends.'
# NewsSearcher: Recent developments in technology have highlighted several key trends shaping various industries:
**Artificial Intelligence (AI) Integration**: AI continues to revolutionize sectors by automating tasks,
enhancing real-time analytics, and improving content delivery. At the 2025 NAB Show, AI's influence is
evident across creator platforms, sports technology, streaming solutions, and cloud architectures.
([tvtechnology.com](https://www.tvtechnology.com/news/nab-show-2025-exhibitor-insight-black-box?utm_source=openai))
...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,94 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from azure.identity import AzureCliCredential
from semantic_kernel.agents import AzureResponsesAgent
from semantic_kernel.connectors.ai.open_ai import AzureOpenAISettings
"""
The following sample demonstrates how to create an OpenAI Responses Agent.
The sample shows how to have the agent answer questions about the provided
document.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the agent service, i.e. the responses are automatically
associated with the thread. Therefore, client code does not need to maintain the
conversation history.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"By birthday, who is the youngest employee?",
"Who works in sales?",
"I have a customer request, who can help me?",
]
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = AzureResponsesAgent.create_client(credential=AzureCliCredential())
pdf_file_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "employees.pdf"
)
with open(pdf_file_path, "rb") as file:
file = await client.files.create(file=file, purpose="assistants")
vector_store = await client.vector_stores.create(
name="step4_responses_agent_file_search",
file_ids=[file.id],
)
file_search_tool = AzureResponsesAgent.configure_file_search_tool(vector_store.id)
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = AzureResponsesAgent(
ai_model_id=AzureOpenAISettings().responses_deployment_name,
client=client,
instructions="Find answers to the user's questions in the provided file.",
name="FileSearch",
tools=[file_search_tool],
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in USER_INPUTS:
print(f"# User: '{user_input}'")
# 4. Invoke the agent for the current message and print the response
async for response in agent.invoke(messages=user_input, thread=thread):
print(f"# Agent: {response.content}")
thread = response.thread
finally:
# 5. Clean up the resources
await client.vector_stores.delete(vector_store.id)
await client.files.delete(file.id)
"""
# User: 'By birthday, who is the youngest employee?'
# Agent: The youngest employee by birthday is Teodor Britton, born on January 9, 1997.
# User: 'Who works in sales?'
# Agent: The employees who work in sales are:
- Mariam Jaslyn, Sales Representative
- Hicran Bea, Sales Manager
- Angelino Embla, Sales Representative.
# User: 'I have a customer request, who can help me?'
# Agent: For a customer request, you could reach out to the following people in the sales department:
- Mariam Jaslyn, Sales Representative
- Hicran Bea, Sales Manager
- Angelino Embla, Sales Representative.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,92 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
from semantic_kernel.contents import ChatMessageContent
from semantic_kernel.contents.image_content import ImageContent
from semantic_kernel.contents.text_content import TextContent
from semantic_kernel.contents.utils.author_role import AuthorRole
"""
The following sample demonstrates how to create an OpenAI Responses Agent.
The sample shows how to have the agent answer questions about the provided images.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the chat history. Therefore, client code does need to
maintain the conversation history if conversation context is desired.
"""
async def main():
# 1. Create the client using OpenAI resources and configuration
client = OpenAIResponsesAgent.create_client()
# 2. Define a file path for an image that will be used in the conversation
file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "resources", "cat.jpg")
# 3. Create a Semantic Kernel agent for the OpenAI Responses API
agent = OpenAIResponsesAgent(
ai_model_id=OpenAISettings().responses_model_id,
client=client,
instructions="Answer questions about the provided images.",
name="VisionAgent",
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
# 4. Define a list of user messages that include text and image content for the vision task
user_messages = [
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="Describe this image."),
ImageContent(
uri="https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/New_york_times_square-terabass.jpg/1200px-New_york_times_square-terabass.jpg"
),
],
),
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="What is the main color in this image?"),
ImageContent(uri="https://upload.wikimedia.org/wikipedia/commons/5/56/White_shark.jpg"),
],
),
ChatMessageContent(
role=AuthorRole.USER,
items=[
TextContent(text="Is there an animal in this image?"),
ImageContent.from_image_file(file_path),
],
),
]
for user_input in user_messages:
print(f"# User: {str(user_input)}") # type: ignore
# 5. Invoke the agent with the current chat history and print the response
response = await agent.get_response(messages=user_input, thread=thread)
print(f"# Agent: {response.content}\n")
thread = response.thread
"""
You should see output similar to the following:
# User: Describe this image.
# Agent: The image depicts a bustling scene of Times Square in New York City...
# User: What is the main color in this image?
# Agent: The main color in the image is blue.
# User: Is there an animal in this image?
# Agent: Yes, there is a cat in the image.
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,98 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import json
from pydantic import BaseModel
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
"""
The following sample demonstrates how to create an OpenAI Responses Agent.
The sample shows how to have the agent provide response using structured outputs.
The interaction with the agent is via the `get_response` method, which sends a
user input to the agent and receives a response from the agent. The conversation
history is maintained by the chat history. Therefore, client code does need to
maintain the conversation history if conversation context is desired.
"""
user_inputs = ["how can I solve 8x + 7y = -23, and 4x=12?"]
# Define the BaseModel we will use for structured outputs
class Step(BaseModel):
explanation: str
output: str
class Reasoning(BaseModel):
steps: list[Step]
final_answer: str
async def main():
# 1. Create the client using OpenAI resources and configuration
# Note: the Azure OpenAI Responses API does not yet support structured outputs.
client = OpenAIResponsesAgent.create_client()
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = OpenAIResponsesAgent(
ai_model_id=OpenAISettings().responses_model_id,
client=client,
instructions="Answer the user's questions.",
name="StructuredOutputsAgent",
text=OpenAIResponsesAgent.configure_response_format(Reasoning),
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
for user_input in user_inputs:
print(f"# User: {str(user_input)}") # type: ignore
# 5. Invoke the agent with the current chat history and print the response
response = await agent.get_response(messages=user_input, thread=thread)
reasoned_result = Reasoning.model_validate_json(response.message.content)
print(f"# {response.name}:\n\n{json.dumps(reasoned_result.model_dump(), indent=4, ensure_ascii=False)}")
thread = response.thread
# 6. Clean up the thread
await thread.delete() if thread else None
"""
# User: how can I solve 8x + 7y = -23, and 4x=12?
# StructuredOutputsAgent:
{
"steps": [
{
"explanation": "First, solve the equation 4x = 12 to find the value of x.",
"output": "4x = 12\nx = 12 / 4\nx = 3"
},
{
"explanation": "Substitute x = 3 into the first equation 8x + 7y = -23.",
"output": "8(3) + 7y = -23"
},
{
"explanation": "Perform the multiplication and simplify the equation.",
"output": "24 + 7y = -23"
},
{
"explanation": "Subtract 24 from both sides to isolate the term with y.",
"output": "7y = -23 - 24\n7y = -47"
},
{
"explanation": "Divide by 7 to solve for y.",
"output": "y = -47 / 7\ny = -6.71 (rounded to two decimal places)"
}
],
"final_answer": "x = 3 and y = -6.71 (rounded to two decimal places)"
}
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,97 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from semantic_kernel.agents import AgentRegistry, OpenAIResponsesAgent
from semantic_kernel.functions import kernel_function
"""
The following sample demonstrates how to create an OpenAI Assistant agent that answers
questions about a sample menu using a Semantic Kernel Plugin. The agent is created
using a yaml declarative spec.
"""
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"How much does that cost?",
"Thank you",
]
# Define the YAML string for the sample
SPEC = """
type: openai_responses
name: Host
instructions: Respond politely to the user's questions.
model:
id: ${OpenAI:ChatModelId}
tools:
- id: MenuPlugin.get_specials
type: function
- id: MenuPlugin.get_item_price
type: function
"""
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
async def main():
# 1. Create the client using Azure OpenAI resources and configuration
client = OpenAIResponsesAgent.create_client()
# 2. Create the assistant on the Azure OpenAI service
agent: OpenAIResponsesAgent = await AgentRegistry.create_from_yaml(
SPEC,
plugins=[MenuPlugin()],
client=client,
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in USER_INPUTS:
print(f"# User: {user_input}")
# 4. Invoke the agent for the specified thread for response
async for response in agent.invoke(
messages=user_input,
thread=thread,
):
print(f"# {response.name}: {response}")
thread = response.thread
finally:
# 5. Clean up the resources
await thread.delete() if thread else None
"""
Sample Output:
# User: Hello
# Agent: Hello! How can I assist you today?
# User: What is the special soup?
# ...
"""
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,13 @@
On a dark winter night, a ghost walks the ramparts of Elsinore Castle in Denmark. Discovered first by a pair of watchmen, then by the scholar Horatio, the ghost resembles the recently deceased King Hamlet, whose brother Claudius has inherited the throne and married the kings widow, Queen Gertrude. When Horatio and the watchmen bring Prince Hamlet, the son of Gertrude and the dead king, to see the ghost, it speaks to him, declaring ominously that it is indeed his fathers spirit, and that he was murdered by none other than Claudius. Ordering Hamlet to seek revenge on the man who usurped his throne and married his wife, the ghost disappears with the dawn.
Prince Hamlet devotes himself to avenging his fathers death, but, because he is contemplative and thoughtful by nature, he delays, entering into a deep melancholy and even apparent madness. Claudius and Gertrude worry about the princes erratic behavior and attempt to discover its cause. They employ a pair of Hamlets friends, Rosencrantz and Guildenstern, to watch him. When Polonius, the pompous Lord Chamberlain, suggests that Hamlet may be mad with love for his daughter, Ophelia, Claudius agrees to spy on Hamlet in conversation with the girl. But though Hamlet certainly seems mad, he does not seem to love Ophelia: he orders her to enter a nunnery and declares that he wishes to ban marriages.
A group of traveling actors comes to Elsinore, and Hamlet seizes upon an idea to test his uncles guilt. He will have the players perform a scene closely resembling the sequence by which Hamlet imagines his uncle to have murdered his father, so that if Claudius is guilty, he will surely react. When the moment of the murder arrives in the theater, Claudius leaps up and leaves the room. Hamlet and Horatio agree that this proves his guilt. Hamlet goes to kill Claudius but finds him praying. Since he believes that killing Claudius while in prayer would send Claudiuss soul to heaven, Hamlet considers that it would be an inadequate revenge and decides to wait. Claudius, now frightened of Hamlets madness and fearing for his own safety, orders that Hamlet be sent to England at once.
Hamlet goes to confront his mother, in whose bedchamber Polonius has hidden behind a tapestry. Hearing a noise from behind the tapestry, Hamlet believes the king is hiding there. He draws his sword and stabs through the fabric, killing Polonius. For this crime, he is immediately dispatched to England with Rosencrantz and Guildenstern. However, Claudiuss plan for Hamlet includes more than banishment, as he has given Rosencrantz and Guildenstern sealed orders for the King of England demanding that Hamlet be put to death.
In the aftermath of her fathers death, Ophelia goes mad with grief and drowns in the river. Poloniuss son, Laertes, who has been staying in France, returns to Denmark in a rage. Claudius convinces him that Hamlet is to blame for his fathers and sisters deaths. When Horatio and the king receive letters from Hamlet indicating that the prince has returned to Denmark after pirates attacked his ship en route to England, Claudius concocts a plan to use Laertes desire for revenge to secure Hamlets death. Laertes will fence with Hamlet in innocent sport, but Claudius will poison Laertes blade so that if he draws blood, Hamlet will die. As a backup plan, the king decides to poison a goblet, which he will give Hamlet to drink should Hamlet score the first or second hits of the match. Hamlet returns to the vicinity of Elsinore just as Ophelias funeral is taking place. Stricken with grief, he attacks Laertes and declares that he had in fact always loved Ophelia. Back at the castle, he tells Horatio that he believes one must be prepared to die, since death can come at any moment. A foolish courtier named Osric arrives on Claudiuss orders to arrange the fencing match between Hamlet and Laertes.
The sword-fighting begins. Hamlet scores the first hit, but declines to drink from the kings proffered goblet. Instead, Gertrude takes a drink from it and is swiftly killed by the poison. Laertes succeeds in wounding Hamlet, though Hamlet does not die of the poison immediately. First, Laertes is cut by his own swords blade, and, after revealing to Hamlet that Claudius is responsible for the queens death, he dies from the blades poison. Hamlet then stabs Claudius through with the poisoned sword and forces him to drink down the rest of the poisoned wine. Claudius dies, and Hamlet dies immediately after achieving his revenge.
At this moment, a Norwegian prince named Fortinbras, who has led an army to Denmark and attacked Poland earlier in the play, enters with ambassadors from England, who report that Rosencrantz and Guildenstern are dead. Fortinbras is stunned by the gruesome sight of the entire royal family lying sprawled on the floor dead. He moves to take power of the kingdom. Horatio, fulfilling Hamlets last request, tells him Hamlets tragic story. Fortinbras orders that Hamlet be carried away in a manner befitting a fallen soldier.
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

@@ -0,0 +1,46 @@
{
"openapi": "3.1.0",
"info": {
"title": "RestCountries.NET API",
"description": "Web API version 3.1 for managing country items, based on previous implementations from restcountries.eu and restcountries.com.",
"version": "v3.1"
},
"servers": [
{ "url": "https://restcountries.net" }
],
"auth": [],
"paths": {
"/v3.1/currency": {
"get": {
"description": "Search by currency.",
"operationId": "LookupCountryByCurrency",
"parameters": [
{
"name": "currency",
"in": "query",
"description": "The currency to search for.",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
},
"components": {
"schemes": {}
}
}
@@ -0,0 +1,701 @@
Segment,Country,Product,Units Sold,Sale Price,Gross Sales,Discounts,Sales,COGS,Profit,Date,Month Number,Month Name,Year
Government,Canada,Carretera,1618.5,20.00,32370.00,0.00,32370.00,16185.00,16185.00,1/1/2014,1,January,2014
Government,Germany,Carretera,1321,20.00,26420.00,0.00,26420.00,13210.00,13210.00,1/1/2014,1,January,2014
Midmarket,France,Carretera,2178,15.00,32670.00,0.00,32670.00,21780.00,10890.00,6/1/2014,6,June,2014
Midmarket,Germany,Carretera,888,15.00,13320.00,0.00,13320.00,8880.00,4440.00,6/1/2014,6,June,2014
Midmarket,Mexico,Carretera,2470,15.00,37050.00,0.00,37050.00,24700.00,12350.00,6/1/2014,6,June,2014
Government,Germany,Carretera,1513,350.00,529550.00,0.00,529550.00,393380.00,136170.00,12/1/2014,12,December,2014
Midmarket,Germany,Montana,921,15.00,13815.00,0.00,13815.00,9210.00,4605.00,3/1/2014,3,March,2014
Channel Partners,Canada,Montana,2518,12.00,30216.00,0.00,30216.00,7554.00,22662.00,6/1/2014,6,June,2014
Government,France,Montana,1899,20.00,37980.00,0.00,37980.00,18990.00,18990.00,6/1/2014,6,June,2014
Channel Partners,Germany,Montana,1545,12.00,18540.00,0.00,18540.00,4635.00,13905.00,6/1/2014,6,June,2014
Midmarket,Mexico,Montana,2470,15.00,37050.00,0.00,37050.00,24700.00,12350.00,6/1/2014,6,June,2014
Enterprise,Canada,Montana,2665.5,125.00,333187.50,0.00,333187.50,319860.00,13327.50,7/1/2014,7,July,2014
Small Business,Mexico,Montana,958,300.00,287400.00,0.00,287400.00,239500.00,47900.00,8/1/2014,8,August,2014
Government,Germany,Montana,2146,7.00,15022.00,0.00,15022.00,10730.00,4292.00,9/1/2014,9,September,2014
Enterprise,Canada,Montana,345,125.00,43125.00,0.00,43125.00,41400.00,1725.00,10/1/2013,10,October,2013
Midmarket,United States of America,Montana,615,15.00,9225.00,0.00,9225.00,6150.00,3075.00,12/1/2014,12,December,2014
Government,Canada,Paseo,292,20.00,5840.00,0.00,5840.00,2920.00,2920.00,2/1/2014,2,February,2014
Midmarket,Mexico,Paseo,974,15.00,14610.00,0.00,14610.00,9740.00,4870.00,2/1/2014,2,February,2014
Channel Partners,Canada,Paseo,2518,12.00,30216.00,0.00,30216.00,7554.00,22662.00,6/1/2014,6,June,2014
Government,Germany,Paseo,1006,350.00,352100.00,0.00,352100.00,261560.00,90540.00,6/1/2014,6,June,2014
Channel Partners,Germany,Paseo,367,12.00,4404.00,0.00,4404.00,1101.00,3303.00,7/1/2014,7,July,2014
Government,Mexico,Paseo,883,7.00,6181.00,0.00,6181.00,4415.00,1766.00,8/1/2014,8,August,2014
Midmarket,France,Paseo,549,15.00,8235.00,0.00,8235.00,5490.00,2745.00,9/1/2013,9,September,2013
Small Business,Mexico,Paseo,788,300.00,236400.00,0.00,236400.00,197000.00,39400.00,9/1/2013,9,September,2013
Midmarket,Mexico,Paseo,2472,15.00,37080.00,0.00,37080.00,24720.00,12360.00,9/1/2014,9,September,2014
Government,United States of America,Paseo,1143,7.00,8001.00,0.00,8001.00,5715.00,2286.00,10/1/2014,10,October,2014
Government,Canada,Paseo,1725,350.00,603750.00,0.00,603750.00,448500.00,155250.00,11/1/2013,11,November,2013
Channel Partners,United States of America,Paseo,912,12.00,10944.00,0.00,10944.00,2736.00,8208.00,11/1/2013,11,November,2013
Midmarket,Canada,Paseo,2152,15.00,32280.00,0.00,32280.00,21520.00,10760.00,12/1/2013,12,December,2013
Government,Canada,Paseo,1817,20.00,36340.00,0.00,36340.00,18170.00,18170.00,12/1/2014,12,December,2014
Government,Germany,Paseo,1513,350.00,529550.00,0.00,529550.00,393380.00,136170.00,12/1/2014,12,December,2014
Government,Mexico,Velo,1493,7.00,10451.00,0.00,10451.00,7465.00,2986.00,1/1/2014,1,January,2014
Enterprise,France,Velo,1804,125.00,225500.00,0.00,225500.00,216480.00,9020.00,2/1/2014,2,February,2014
Channel Partners,Germany,Velo,2161,12.00,25932.00,0.00,25932.00,6483.00,19449.00,3/1/2014,3,March,2014
Government,Germany,Velo,1006,350.00,352100.00,0.00,352100.00,261560.00,90540.00,6/1/2014,6,June,2014
Channel Partners,Germany,Velo,1545,12.00,18540.00,0.00,18540.00,4635.00,13905.00,6/1/2014,6,June,2014
Enterprise,United States of America,Velo,2821,125.00,352625.00,0.00,352625.00,338520.00,14105.00,8/1/2014,8,August,2014
Enterprise,Canada,Velo,345,125.00,43125.00,0.00,43125.00,41400.00,1725.00,10/1/2013,10,October,2013
Small Business,Canada,VTT,2001,300.00,600300.00,0.00,600300.00,500250.00,100050.00,2/1/2014,2,February,2014
Channel Partners,Germany,VTT,2838,12.00,34056.00,0.00,34056.00,8514.00,25542.00,4/1/2014,4,April,2014
Midmarket,France,VTT,2178,15.00,32670.00,0.00,32670.00,21780.00,10890.00,6/1/2014,6,June,2014
Midmarket,Germany,VTT,888,15.00,13320.00,0.00,13320.00,8880.00,4440.00,6/1/2014,6,June,2014
Government,France,VTT,1527,350.00,534450.00,0.00,534450.00,397020.00,137430.00,9/1/2013,9,September,2013
Small Business,France,VTT,2151,300.00,645300.00,0.00,645300.00,537750.00,107550.00,9/1/2014,9,September,2014
Government,Canada,VTT,1817,20.00,36340.00,0.00,36340.00,18170.00,18170.00,12/1/2014,12,December,2014
Government,France,Amarilla,2750,350.00,962500.00,0.00,962500.00,715000.00,247500.00,2/1/2014,2,February,2014
Channel Partners,United States of America,Amarilla,1953,12.00,23436.00,0.00,23436.00,5859.00,17577.00,4/1/2014,4,April,2014
Enterprise,Germany,Amarilla,4219.5,125.00,527437.50,0.00,527437.50,506340.00,21097.50,4/1/2014,4,April,2014
Government,France,Amarilla,1899,20.00,37980.00,0.00,37980.00,18990.00,18990.00,6/1/2014,6,June,2014
Government,Germany,Amarilla,1686,7.00,11802.00,0.00,11802.00,8430.00,3372.00,7/1/2014,7,July,2014
Channel Partners,United States of America,Amarilla,2141,12.00,25692.00,0.00,25692.00,6423.00,19269.00,8/1/2014,8,August,2014
Government,United States of America,Amarilla,1143,7.00,8001.00,0.00,8001.00,5715.00,2286.00,10/1/2014,10,October,2014
Midmarket,United States of America,Amarilla,615,15.00,9225.00,0.00,9225.00,6150.00,3075.00,12/1/2014,12,December,2014
Government,France,Paseo,3945,7.00,27615.00,276.15,27338.85,19725.00,7613.85,1/1/2014,1,January,2014
Midmarket,France,Paseo,2296,15.00,34440.00,344.40,34095.60,22960.00,11135.60,2/1/2014,2,February,2014
Government,France,Paseo,1030,7.00,7210.00,72.10,7137.90,5150.00,1987.90,5/1/2014,5,May,2014
Government,France,Velo,639,7.00,4473.00,44.73,4428.27,3195.00,1233.27,11/1/2014,11,November,2014
Government,Canada,VTT,1326,7.00,9282.00,92.82,9189.18,6630.00,2559.18,3/1/2014,3,March,2014
Channel Partners,United States of America,Carretera,1858,12.00,22296.00,222.96,22073.04,5574.00,16499.04,2/1/2014,2,February,2014
Government,Mexico,Carretera,1210,350.00,423500.00,4235.00,419265.00,314600.00,104665.00,3/1/2014,3,March,2014
Government,United States of America,Carretera,2529,7.00,17703.00,177.03,17525.97,12645.00,4880.97,7/1/2014,7,July,2014
Channel Partners,Canada,Carretera,1445,12.00,17340.00,173.40,17166.60,4335.00,12831.60,9/1/2014,9,September,2014
Enterprise,United States of America,Carretera,330,125.00,41250.00,412.50,40837.50,39600.00,1237.50,9/1/2013,9,September,2013
Channel Partners,France,Carretera,2671,12.00,32052.00,320.52,31731.48,8013.00,23718.48,9/1/2014,9,September,2014
Channel Partners,Germany,Carretera,766,12.00,9192.00,91.92,9100.08,2298.00,6802.08,10/1/2013,10,October,2013
Small Business,Mexico,Carretera,494,300.00,148200.00,1482.00,146718.00,123500.00,23218.00,10/1/2013,10,October,2013
Government,Mexico,Carretera,1397,350.00,488950.00,4889.50,484060.50,363220.00,120840.50,10/1/2014,10,October,2014
Government,France,Carretera,2155,350.00,754250.00,7542.50,746707.50,560300.00,186407.50,12/1/2014,12,December,2014
Midmarket,Mexico,Montana,2214,15.00,33210.00,332.10,32877.90,22140.00,10737.90,3/1/2014,3,March,2014
Small Business,United States of America,Montana,2301,300.00,690300.00,6903.00,683397.00,575250.00,108147.00,4/1/2014,4,April,2014
Government,France,Montana,1375.5,20.00,27510.00,275.10,27234.90,13755.00,13479.90,7/1/2014,7,July,2014
Government,Canada,Montana,1830,7.00,12810.00,128.10,12681.90,9150.00,3531.90,8/1/2014,8,August,2014
Small Business,United States of America,Montana,2498,300.00,749400.00,7494.00,741906.00,624500.00,117406.00,9/1/2013,9,September,2013
Enterprise,United States of America,Montana,663,125.00,82875.00,828.75,82046.25,79560.00,2486.25,10/1/2013,10,October,2013
Midmarket,United States of America,Paseo,1514,15.00,22710.00,227.10,22482.90,15140.00,7342.90,2/1/2014,2,February,2014
Government,United States of America,Paseo,4492.5,7.00,31447.50,314.48,31133.03,22462.50,8670.53,4/1/2014,4,April,2014
Enterprise,United States of America,Paseo,727,125.00,90875.00,908.75,89966.25,87240.00,2726.25,6/1/2014,6,June,2014
Enterprise,France,Paseo,787,125.00,98375.00,983.75,97391.25,94440.00,2951.25,6/1/2014,6,June,2014
Enterprise,Mexico,Paseo,1823,125.00,227875.00,2278.75,225596.25,218760.00,6836.25,7/1/2014,7,July,2014
Midmarket,Germany,Paseo,747,15.00,11205.00,112.05,11092.95,7470.00,3622.95,9/1/2014,9,September,2014
Channel Partners,Germany,Paseo,766,12.00,9192.00,91.92,9100.08,2298.00,6802.08,10/1/2013,10,October,2013
Small Business,United States of America,Paseo,2905,300.00,871500.00,8715.00,862785.00,726250.00,136535.00,11/1/2014,11,November,2014
Government,France,Paseo,2155,350.00,754250.00,7542.50,746707.50,560300.00,186407.50,12/1/2014,12,December,2014
Government,France,Velo,3864,20.00,77280.00,772.80,76507.20,38640.00,37867.20,4/1/2014,4,April,2014
Government,Mexico,Velo,362,7.00,2534.00,25.34,2508.66,1810.00,698.66,5/1/2014,5,May,2014
Enterprise,Canada,Velo,923,125.00,115375.00,1153.75,114221.25,110760.00,3461.25,8/1/2014,8,August,2014
Enterprise,United States of America,Velo,663,125.00,82875.00,828.75,82046.25,79560.00,2486.25,10/1/2013,10,October,2013
Government,Canada,Velo,2092,7.00,14644.00,146.44,14497.56,10460.00,4037.56,11/1/2013,11,November,2013
Government,Germany,VTT,263,7.00,1841.00,18.41,1822.59,1315.00,507.59,3/1/2014,3,March,2014
Government,Canada,VTT,943.5,350.00,330225.00,3302.25,326922.75,245310.00,81612.75,4/1/2014,4,April,2014
Enterprise,United States of America,VTT,727,125.00,90875.00,908.75,89966.25,87240.00,2726.25,6/1/2014,6,June,2014
Enterprise,France,VTT,787,125.00,98375.00,983.75,97391.25,94440.00,2951.25,6/1/2014,6,June,2014
Small Business,Germany,VTT,986,300.00,295800.00,2958.00,292842.00,246500.00,46342.00,9/1/2014,9,September,2014
Small Business,Mexico,VTT,494,300.00,148200.00,1482.00,146718.00,123500.00,23218.00,10/1/2013,10,October,2013
Government,Mexico,VTT,1397,350.00,488950.00,4889.50,484060.50,363220.00,120840.50,10/1/2014,10,October,2014
Enterprise,France,VTT,1744,125.00,218000.00,2180.00,215820.00,209280.00,6540.00,11/1/2014,11,November,2014
Channel Partners,United States of America,Amarilla,1989,12.00,23868.00,238.68,23629.32,5967.00,17662.32,9/1/2013,9,September,2013
Midmarket,France,Amarilla,321,15.00,4815.00,48.15,4766.85,3210.00,1556.85,11/1/2013,11,November,2013
Enterprise,Canada,Carretera,742.5,125.00,92812.50,1856.25,90956.25,89100.00,1856.25,4/1/2014,4,April,2014
Channel Partners,Canada,Carretera,1295,12.00,15540.00,310.80,15229.20,3885.00,11344.20,10/1/2014,10,October,2014
Small Business,Germany,Carretera,214,300.00,64200.00,1284.00,62916.00,53500.00,9416.00,10/1/2013,10,October,2013
Government,France,Carretera,2145,7.00,15015.00,300.30,14714.70,10725.00,3989.70,11/1/2013,11,November,2013
Government,Canada,Carretera,2852,350.00,998200.00,19964.00,978236.00,741520.00,236716.00,12/1/2014,12,December,2014
Channel Partners,United States of America,Montana,1142,12.00,13704.00,274.08,13429.92,3426.00,10003.92,6/1/2014,6,June,2014
Government,United States of America,Montana,1566,20.00,31320.00,626.40,30693.60,15660.00,15033.60,10/1/2014,10,October,2014
Channel Partners,Mexico,Montana,690,12.00,8280.00,165.60,8114.40,2070.00,6044.40,11/1/2014,11,November,2014
Enterprise,Mexico,Montana,1660,125.00,207500.00,4150.00,203350.00,199200.00,4150.00,11/1/2013,11,November,2013
Midmarket,Canada,Paseo,2363,15.00,35445.00,708.90,34736.10,23630.00,11106.10,2/1/2014,2,February,2014
Small Business,France,Paseo,918,300.00,275400.00,5508.00,269892.00,229500.00,40392.00,5/1/2014,5,May,2014
Small Business,Germany,Paseo,1728,300.00,518400.00,10368.00,508032.00,432000.00,76032.00,5/1/2014,5,May,2014
Channel Partners,United States of America,Paseo,1142,12.00,13704.00,274.08,13429.92,3426.00,10003.92,6/1/2014,6,June,2014
Enterprise,Mexico,Paseo,662,125.00,82750.00,1655.00,81095.00,79440.00,1655.00,6/1/2014,6,June,2014
Channel Partners,Canada,Paseo,1295,12.00,15540.00,310.80,15229.20,3885.00,11344.20,10/1/2014,10,October,2014
Enterprise,Germany,Paseo,809,125.00,101125.00,2022.50,99102.50,97080.00,2022.50,10/1/2013,10,October,2013
Enterprise,Mexico,Paseo,2145,125.00,268125.00,5362.50,262762.50,257400.00,5362.50,10/1/2013,10,October,2013
Channel Partners,France,Paseo,1785,12.00,21420.00,428.40,20991.60,5355.00,15636.60,11/1/2013,11,November,2013
Small Business,Canada,Paseo,1916,300.00,574800.00,11496.00,563304.00,479000.00,84304.00,12/1/2014,12,December,2014
Government,Canada,Paseo,2852,350.00,998200.00,19964.00,978236.00,741520.00,236716.00,12/1/2014,12,December,2014
Enterprise,Canada,Paseo,2729,125.00,341125.00,6822.50,334302.50,327480.00,6822.50,12/1/2014,12,December,2014
Midmarket,United States of America,Paseo,1925,15.00,28875.00,577.50,28297.50,19250.00,9047.50,12/1/2013,12,December,2013
Government,United States of America,Paseo,2013,7.00,14091.00,281.82,13809.18,10065.00,3744.18,12/1/2013,12,December,2013
Channel Partners,France,Paseo,1055,12.00,12660.00,253.20,12406.80,3165.00,9241.80,12/1/2014,12,December,2014
Channel Partners,Mexico,Paseo,1084,12.00,13008.00,260.16,12747.84,3252.00,9495.84,12/1/2014,12,December,2014
Government,United States of America,Velo,1566,20.00,31320.00,626.40,30693.60,15660.00,15033.60,10/1/2014,10,October,2014
Government,Germany,Velo,2966,350.00,1038100.00,20762.00,1017338.00,771160.00,246178.00,10/1/2013,10,October,2013
Government,Germany,Velo,2877,350.00,1006950.00,20139.00,986811.00,748020.00,238791.00,10/1/2014,10,October,2014
Enterprise,Germany,Velo,809,125.00,101125.00,2022.50,99102.50,97080.00,2022.50,10/1/2013,10,October,2013
Enterprise,Mexico,Velo,2145,125.00,268125.00,5362.50,262762.50,257400.00,5362.50,10/1/2013,10,October,2013
Channel Partners,France,Velo,1055,12.00,12660.00,253.20,12406.80,3165.00,9241.80,12/1/2014,12,December,2014
Government,Mexico,Velo,544,20.00,10880.00,217.60,10662.40,5440.00,5222.40,12/1/2013,12,December,2013
Channel Partners,Mexico,Velo,1084,12.00,13008.00,260.16,12747.84,3252.00,9495.84,12/1/2014,12,December,2014
Enterprise,Mexico,VTT,662,125.00,82750.00,1655.00,81095.00,79440.00,1655.00,6/1/2014,6,June,2014
Small Business,Germany,VTT,214,300.00,64200.00,1284.00,62916.00,53500.00,9416.00,10/1/2013,10,October,2013
Government,Germany,VTT,2877,350.00,1006950.00,20139.00,986811.00,748020.00,238791.00,10/1/2014,10,October,2014
Enterprise,Canada,VTT,2729,125.00,341125.00,6822.50,334302.50,327480.00,6822.50,12/1/2014,12,December,2014
Government,United States of America,VTT,266,350.00,93100.00,1862.00,91238.00,69160.00,22078.00,12/1/2013,12,December,2013
Government,Mexico,VTT,1940,350.00,679000.00,13580.00,665420.00,504400.00,161020.00,12/1/2013,12,December,2013
Small Business,Germany,Amarilla,259,300.00,77700.00,1554.00,76146.00,64750.00,11396.00,3/1/2014,3,March,2014
Small Business,Mexico,Amarilla,1101,300.00,330300.00,6606.00,323694.00,275250.00,48444.00,3/1/2014,3,March,2014
Enterprise,Germany,Amarilla,2276,125.00,284500.00,5690.00,278810.00,273120.00,5690.00,5/1/2014,5,May,2014
Government,Germany,Amarilla,2966,350.00,1038100.00,20762.00,1017338.00,771160.00,246178.00,10/1/2013,10,October,2013
Government,United States of America,Amarilla,1236,20.00,24720.00,494.40,24225.60,12360.00,11865.60,11/1/2014,11,November,2014
Government,France,Amarilla,941,20.00,18820.00,376.40,18443.60,9410.00,9033.60,11/1/2014,11,November,2014
Small Business,Canada,Amarilla,1916,300.00,574800.00,11496.00,563304.00,479000.00,84304.00,12/1/2014,12,December,2014
Enterprise,France,Carretera,4243.5,125.00,530437.50,15913.13,514524.38,509220.00,5304.38,4/1/2014,4,April,2014
Government,Germany,Carretera,2580,20.00,51600.00,1548.00,50052.00,25800.00,24252.00,4/1/2014,4,April,2014
Small Business,Germany,Carretera,689,300.00,206700.00,6201.00,200499.00,172250.00,28249.00,6/1/2014,6,June,2014
Channel Partners,United States of America,Carretera,1947,12.00,23364.00,700.92,22663.08,5841.00,16822.08,9/1/2014,9,September,2014
Channel Partners,Canada,Carretera,908,12.00,10896.00,326.88,10569.12,2724.00,7845.12,12/1/2013,12,December,2013
Government,Germany,Montana,1958,7.00,13706.00,411.18,13294.82,9790.00,3504.82,2/1/2014,2,February,2014
Channel Partners,France,Montana,1901,12.00,22812.00,684.36,22127.64,5703.00,16424.64,6/1/2014,6,June,2014
Government,France,Montana,544,7.00,3808.00,114.24,3693.76,2720.00,973.76,9/1/2014,9,September,2014
Government,Germany,Montana,1797,350.00,628950.00,18868.50,610081.50,467220.00,142861.50,9/1/2013,9,September,2013
Enterprise,France,Montana,1287,125.00,160875.00,4826.25,156048.75,154440.00,1608.75,12/1/2014,12,December,2014
Enterprise,Germany,Montana,1706,125.00,213250.00,6397.50,206852.50,204720.00,2132.50,12/1/2014,12,December,2014
Small Business,France,Paseo,2434.5,300.00,730350.00,21910.50,708439.50,608625.00,99814.50,1/1/2014,1,January,2014
Enterprise,Canada,Paseo,1774,125.00,221750.00,6652.50,215097.50,212880.00,2217.50,3/1/2014,3,March,2014
Channel Partners,France,Paseo,1901,12.00,22812.00,684.36,22127.64,5703.00,16424.64,6/1/2014,6,June,2014
Small Business,Germany,Paseo,689,300.00,206700.00,6201.00,200499.00,172250.00,28249.00,6/1/2014,6,June,2014
Enterprise,Germany,Paseo,1570,125.00,196250.00,5887.50,190362.50,188400.00,1962.50,6/1/2014,6,June,2014
Channel Partners,United States of America,Paseo,1369.5,12.00,16434.00,493.02,15940.98,4108.50,11832.48,7/1/2014,7,July,2014
Enterprise,Canada,Paseo,2009,125.00,251125.00,7533.75,243591.25,241080.00,2511.25,10/1/2014,10,October,2014
Midmarket,Germany,Paseo,1945,15.00,29175.00,875.25,28299.75,19450.00,8849.75,10/1/2013,10,October,2013
Enterprise,France,Paseo,1287,125.00,160875.00,4826.25,156048.75,154440.00,1608.75,12/1/2014,12,December,2014
Enterprise,Germany,Paseo,1706,125.00,213250.00,6397.50,206852.50,204720.00,2132.50,12/1/2014,12,December,2014
Enterprise,Canada,Velo,2009,125.00,251125.00,7533.75,243591.25,241080.00,2511.25,10/1/2014,10,October,2014
Small Business,United States of America,VTT,2844,300.00,853200.00,25596.00,827604.00,711000.00,116604.00,2/1/2014,2,February,2014
Channel Partners,Mexico,VTT,1916,12.00,22992.00,689.76,22302.24,5748.00,16554.24,4/1/2014,4,April,2014
Enterprise,Germany,VTT,1570,125.00,196250.00,5887.50,190362.50,188400.00,1962.50,6/1/2014,6,June,2014
Small Business,Canada,VTT,1874,300.00,562200.00,16866.00,545334.00,468500.00,76834.00,8/1/2014,8,August,2014
Government,Mexico,VTT,1642,350.00,574700.00,17241.00,557459.00,426920.00,130539.00,8/1/2014,8,August,2014
Midmarket,Germany,VTT,1945,15.00,29175.00,875.25,28299.75,19450.00,8849.75,10/1/2013,10,October,2013
Government,Canada,Carretera,831,20.00,16620.00,498.60,16121.40,8310.00,7811.40,5/1/2014,5,May,2014
Government,Mexico,Paseo,1760,7.00,12320.00,369.60,11950.40,8800.00,3150.40,9/1/2013,9,September,2013
Government,Canada,Velo,3850.5,20.00,77010.00,2310.30,74699.70,38505.00,36194.70,4/1/2014,4,April,2014
Channel Partners,Germany,VTT,2479,12.00,29748.00,892.44,28855.56,7437.00,21418.56,1/1/2014,1,January,2014
Midmarket,Mexico,Montana,2031,15.00,30465.00,1218.60,29246.40,20310.00,8936.40,10/1/2014,10,October,2014
Midmarket,Mexico,Paseo,2031,15.00,30465.00,1218.60,29246.40,20310.00,8936.40,10/1/2014,10,October,2014
Midmarket,France,Paseo,2261,15.00,33915.00,1356.60,32558.40,22610.00,9948.40,12/1/2013,12,December,2013
Government,United States of America,Velo,736,20.00,14720.00,588.80,14131.20,7360.00,6771.20,9/1/2013,9,September,2013
Government,Canada,Carretera,2851,7.00,19957.00,798.28,19158.72,14255.00,4903.72,10/1/2013,10,October,2013
Small Business,Germany,Carretera,2021,300.00,606300.00,24252.00,582048.00,505250.00,76798.00,10/1/2014,10,October,2014
Government,United States of America,Carretera,274,350.00,95900.00,3836.00,92064.00,71240.00,20824.00,12/1/2014,12,December,2014
Midmarket,Canada,Montana,1967,15.00,29505.00,1180.20,28324.80,19670.00,8654.80,3/1/2014,3,March,2014
Small Business,Germany,Montana,1859,300.00,557700.00,22308.00,535392.00,464750.00,70642.00,8/1/2014,8,August,2014
Government,Canada,Montana,2851,7.00,19957.00,798.28,19158.72,14255.00,4903.72,10/1/2013,10,October,2013
Small Business,Germany,Montana,2021,300.00,606300.00,24252.00,582048.00,505250.00,76798.00,10/1/2014,10,October,2014
Enterprise,Mexico,Montana,1138,125.00,142250.00,5690.00,136560.00,136560.00,0.00,12/1/2014,12,December,2014
Government,Canada,Paseo,4251,7.00,29757.00,1190.28,28566.72,21255.00,7311.72,1/1/2014,1,January,2014
Enterprise,Germany,Paseo,795,125.00,99375.00,3975.00,95400.00,95400.00,0.00,3/1/2014,3,March,2014
Small Business,Germany,Paseo,1414.5,300.00,424350.00,16974.00,407376.00,353625.00,53751.00,4/1/2014,4,April,2014
Small Business,United States of America,Paseo,2918,300.00,875400.00,35016.00,840384.00,729500.00,110884.00,5/1/2014,5,May,2014
Government,United States of America,Paseo,3450,350.00,1207500.00,48300.00,1159200.00,897000.00,262200.00,7/1/2014,7,July,2014
Enterprise,France,Paseo,2988,125.00,373500.00,14940.00,358560.00,358560.00,0.00,7/1/2014,7,July,2014
Midmarket,Canada,Paseo,218,15.00,3270.00,130.80,3139.20,2180.00,959.20,9/1/2014,9,September,2014
Government,Canada,Paseo,2074,20.00,41480.00,1659.20,39820.80,20740.00,19080.80,9/1/2014,9,September,2014
Government,United States of America,Paseo,1056,20.00,21120.00,844.80,20275.20,10560.00,9715.20,9/1/2014,9,September,2014
Midmarket,United States of America,Paseo,671,15.00,10065.00,402.60,9662.40,6710.00,2952.40,10/1/2013,10,October,2013
Midmarket,Mexico,Paseo,1514,15.00,22710.00,908.40,21801.60,15140.00,6661.60,10/1/2013,10,October,2013
Government,United States of America,Paseo,274,350.00,95900.00,3836.00,92064.00,71240.00,20824.00,12/1/2014,12,December,2014
Enterprise,Mexico,Paseo,1138,125.00,142250.00,5690.00,136560.00,136560.00,0.00,12/1/2014,12,December,2014
Channel Partners,United States of America,Velo,1465,12.00,17580.00,703.20,16876.80,4395.00,12481.80,3/1/2014,3,March,2014
Government,Canada,Velo,2646,20.00,52920.00,2116.80,50803.20,26460.00,24343.20,9/1/2013,9,September,2013
Government,France,Velo,2177,350.00,761950.00,30478.00,731472.00,566020.00,165452.00,10/1/2014,10,October,2014
Channel Partners,France,VTT,866,12.00,10392.00,415.68,9976.32,2598.00,7378.32,5/1/2014,5,May,2014
Government,United States of America,VTT,349,350.00,122150.00,4886.00,117264.00,90740.00,26524.00,9/1/2013,9,September,2013
Government,France,VTT,2177,350.00,761950.00,30478.00,731472.00,566020.00,165452.00,10/1/2014,10,October,2014
Midmarket,Mexico,VTT,1514,15.00,22710.00,908.40,21801.60,15140.00,6661.60,10/1/2013,10,October,2013
Government,Mexico,Amarilla,1865,350.00,652750.00,26110.00,626640.00,484900.00,141740.00,2/1/2014,2,February,2014
Enterprise,Mexico,Amarilla,1074,125.00,134250.00,5370.00,128880.00,128880.00,0.00,4/1/2014,4,April,2014
Government,Germany,Amarilla,1907,350.00,667450.00,26698.00,640752.00,495820.00,144932.00,9/1/2014,9,September,2014
Midmarket,United States of America,Amarilla,671,15.00,10065.00,402.60,9662.40,6710.00,2952.40,10/1/2013,10,October,2013
Government,Canada,Amarilla,1778,350.00,622300.00,24892.00,597408.00,462280.00,135128.00,12/1/2013,12,December,2013
Government,Germany,Montana,1159,7.00,8113.00,405.65,7707.35,5795.00,1912.35,10/1/2013,10,October,2013
Government,Germany,Paseo,1372,7.00,9604.00,480.20,9123.80,6860.00,2263.80,1/1/2014,1,January,2014
Government,Canada,Paseo,2349,7.00,16443.00,822.15,15620.85,11745.00,3875.85,9/1/2013,9,September,2013
Government,Mexico,Paseo,2689,7.00,18823.00,941.15,17881.85,13445.00,4436.85,10/1/2014,10,October,2014
Channel Partners,Canada,Paseo,2431,12.00,29172.00,1458.60,27713.40,7293.00,20420.40,12/1/2014,12,December,2014
Channel Partners,Canada,Velo,2431,12.00,29172.00,1458.60,27713.40,7293.00,20420.40,12/1/2014,12,December,2014
Government,Mexico,VTT,2689,7.00,18823.00,941.15,17881.85,13445.00,4436.85,10/1/2014,10,October,2014
Government,Mexico,Amarilla,1683,7.00,11781.00,589.05,11191.95,8415.00,2776.95,7/1/2014,7,July,2014
Channel Partners,Mexico,Amarilla,1123,12.00,13476.00,673.80,12802.20,3369.00,9433.20,8/1/2014,8,August,2014
Government,Germany,Amarilla,1159,7.00,8113.00,405.65,7707.35,5795.00,1912.35,10/1/2013,10,October,2013
Channel Partners,France,Carretera,1865,12.00,22380.00,1119.00,21261.00,5595.00,15666.00,2/1/2014,2,February,2014
Channel Partners,Germany,Carretera,1116,12.00,13392.00,669.60,12722.40,3348.00,9374.40,2/1/2014,2,February,2014
Government,France,Carretera,1563,20.00,31260.00,1563.00,29697.00,15630.00,14067.00,5/1/2014,5,May,2014
Small Business,United States of America,Carretera,991,300.00,297300.00,14865.00,282435.00,247750.00,34685.00,6/1/2014,6,June,2014
Government,Germany,Carretera,1016,7.00,7112.00,355.60,6756.40,5080.00,1676.40,11/1/2013,11,November,2013
Midmarket,Mexico,Carretera,2791,15.00,41865.00,2093.25,39771.75,27910.00,11861.75,11/1/2014,11,November,2014
Government,United States of America,Carretera,570,7.00,3990.00,199.50,3790.50,2850.00,940.50,12/1/2014,12,December,2014
Government,France,Carretera,2487,7.00,17409.00,870.45,16538.55,12435.00,4103.55,12/1/2014,12,December,2014
Government,France,Montana,1384.5,350.00,484575.00,24228.75,460346.25,359970.00,100376.25,1/1/2014,1,January,2014
Enterprise,United States of America,Montana,3627,125.00,453375.00,22668.75,430706.25,435240.00,-4533.75,7/1/2014,7,July,2014
Government,Mexico,Montana,720,350.00,252000.00,12600.00,239400.00,187200.00,52200.00,9/1/2013,9,September,2013
Channel Partners,Germany,Montana,2342,12.00,28104.00,1405.20,26698.80,7026.00,19672.80,11/1/2014,11,November,2014
Small Business,Mexico,Montana,1100,300.00,330000.00,16500.00,313500.00,275000.00,38500.00,12/1/2013,12,December,2013
Government,France,Paseo,1303,20.00,26060.00,1303.00,24757.00,13030.00,11727.00,2/1/2014,2,February,2014
Enterprise,United States of America,Paseo,2992,125.00,374000.00,18700.00,355300.00,359040.00,-3740.00,3/1/2014,3,March,2014
Enterprise,France,Paseo,2385,125.00,298125.00,14906.25,283218.75,286200.00,-2981.25,3/1/2014,3,March,2014
Small Business,Mexico,Paseo,1607,300.00,482100.00,24105.00,457995.00,401750.00,56245.00,4/1/2014,4,April,2014
Government,United States of America,Paseo,2327,7.00,16289.00,814.45,15474.55,11635.00,3839.55,5/1/2014,5,May,2014
Small Business,United States of America,Paseo,991,300.00,297300.00,14865.00,282435.00,247750.00,34685.00,6/1/2014,6,June,2014
Government,United States of America,Paseo,602,350.00,210700.00,10535.00,200165.00,156520.00,43645.00,6/1/2014,6,June,2014
Midmarket,France,Paseo,2620,15.00,39300.00,1965.00,37335.00,26200.00,11135.00,9/1/2014,9,September,2014
Government,Canada,Paseo,1228,350.00,429800.00,21490.00,408310.00,319280.00,89030.00,10/1/2013,10,October,2013
Government,Canada,Paseo,1389,20.00,27780.00,1389.00,26391.00,13890.00,12501.00,10/1/2013,10,October,2013
Enterprise,United States of America,Paseo,861,125.00,107625.00,5381.25,102243.75,103320.00,-1076.25,10/1/2014,10,October,2014
Enterprise,France,Paseo,704,125.00,88000.00,4400.00,83600.00,84480.00,-880.00,10/1/2013,10,October,2013
Government,Canada,Paseo,1802,20.00,36040.00,1802.00,34238.00,18020.00,16218.00,12/1/2013,12,December,2013
Government,United States of America,Paseo,2663,20.00,53260.00,2663.00,50597.00,26630.00,23967.00,12/1/2014,12,December,2014
Government,France,Paseo,2136,7.00,14952.00,747.60,14204.40,10680.00,3524.40,12/1/2013,12,December,2013
Midmarket,Germany,Paseo,2116,15.00,31740.00,1587.00,30153.00,21160.00,8993.00,12/1/2013,12,December,2013
Midmarket,United States of America,Velo,555,15.00,8325.00,416.25,7908.75,5550.00,2358.75,1/1/2014,1,January,2014
Midmarket,Mexico,Velo,2861,15.00,42915.00,2145.75,40769.25,28610.00,12159.25,1/1/2014,1,January,2014
Enterprise,Germany,Velo,807,125.00,100875.00,5043.75,95831.25,96840.00,-1008.75,2/1/2014,2,February,2014
Government,United States of America,Velo,602,350.00,210700.00,10535.00,200165.00,156520.00,43645.00,6/1/2014,6,June,2014
Government,United States of America,Velo,2832,20.00,56640.00,2832.00,53808.00,28320.00,25488.00,8/1/2014,8,August,2014
Government,France,Velo,1579,20.00,31580.00,1579.00,30001.00,15790.00,14211.00,8/1/2014,8,August,2014
Enterprise,United States of America,Velo,861,125.00,107625.00,5381.25,102243.75,103320.00,-1076.25,10/1/2014,10,October,2014
Enterprise,France,Velo,704,125.00,88000.00,4400.00,83600.00,84480.00,-880.00,10/1/2013,10,October,2013
Government,France,Velo,1033,20.00,20660.00,1033.00,19627.00,10330.00,9297.00,12/1/2013,12,December,2013
Small Business,Germany,Velo,1250,300.00,375000.00,18750.00,356250.00,312500.00,43750.00,12/1/2014,12,December,2014
Government,Canada,VTT,1389,20.00,27780.00,1389.00,26391.00,13890.00,12501.00,10/1/2013,10,October,2013
Government,United States of America,VTT,1265,20.00,25300.00,1265.00,24035.00,12650.00,11385.00,11/1/2013,11,November,2013
Government,Germany,VTT,2297,20.00,45940.00,2297.00,43643.00,22970.00,20673.00,11/1/2013,11,November,2013
Government,United States of America,VTT,2663,20.00,53260.00,2663.00,50597.00,26630.00,23967.00,12/1/2014,12,December,2014
Government,United States of America,VTT,570,7.00,3990.00,199.50,3790.50,2850.00,940.50,12/1/2014,12,December,2014
Government,France,VTT,2487,7.00,17409.00,870.45,16538.55,12435.00,4103.55,12/1/2014,12,December,2014
Government,Germany,Amarilla,1350,350.00,472500.00,23625.00,448875.00,351000.00,97875.00,2/1/2014,2,February,2014
Government,Canada,Amarilla,552,350.00,193200.00,9660.00,183540.00,143520.00,40020.00,8/1/2014,8,August,2014
Government,Canada,Amarilla,1228,350.00,429800.00,21490.00,408310.00,319280.00,89030.00,10/1/2013,10,October,2013
Small Business,Germany,Amarilla,1250,300.00,375000.00,18750.00,356250.00,312500.00,43750.00,12/1/2014,12,December,2014
Midmarket,France,Paseo,3801,15.00,57015.00,3420.90,53594.10,38010.00,15584.10,4/1/2014,4,April,2014
Government,United States of America,Carretera,1117.5,20.00,22350.00,1341.00,21009.00,11175.00,9834.00,1/1/2014,1,January,2014
Midmarket,Canada,Carretera,2844,15.00,42660.00,2559.60,40100.40,28440.00,11660.40,6/1/2014,6,June,2014
Channel Partners,Mexico,Carretera,562,12.00,6744.00,404.64,6339.36,1686.00,4653.36,9/1/2014,9,September,2014
Channel Partners,Canada,Carretera,2299,12.00,27588.00,1655.28,25932.72,6897.00,19035.72,10/1/2013,10,October,2013
Midmarket,United States of America,Carretera,2030,15.00,30450.00,1827.00,28623.00,20300.00,8323.00,11/1/2014,11,November,2014
Government,United States of America,Carretera,263,7.00,1841.00,110.46,1730.54,1315.00,415.54,11/1/2013,11,November,2013
Enterprise,Germany,Carretera,887,125.00,110875.00,6652.50,104222.50,106440.00,-2217.50,12/1/2013,12,December,2013
Government,Mexico,Montana,980,350.00,343000.00,20580.00,322420.00,254800.00,67620.00,4/1/2014,4,April,2014
Government,Germany,Montana,1460,350.00,511000.00,30660.00,480340.00,379600.00,100740.00,5/1/2014,5,May,2014
Government,France,Montana,1403,7.00,9821.00,589.26,9231.74,7015.00,2216.74,10/1/2013,10,October,2013
Channel Partners,United States of America,Montana,2723,12.00,32676.00,1960.56,30715.44,8169.00,22546.44,11/1/2014,11,November,2014
Government,France,Paseo,1496,350.00,523600.00,31416.00,492184.00,388960.00,103224.00,6/1/2014,6,June,2014
Channel Partners,Canada,Paseo,2299,12.00,27588.00,1655.28,25932.72,6897.00,19035.72,10/1/2013,10,October,2013
Government,United States of America,Paseo,727,350.00,254450.00,15267.00,239183.00,189020.00,50163.00,10/1/2013,10,October,2013
Enterprise,Canada,Velo,952,125.00,119000.00,7140.00,111860.00,114240.00,-2380.00,2/1/2014,2,February,2014
Enterprise,United States of America,Velo,2755,125.00,344375.00,20662.50,323712.50,330600.00,-6887.50,2/1/2014,2,February,2014
Midmarket,Germany,Velo,1530,15.00,22950.00,1377.00,21573.00,15300.00,6273.00,5/1/2014,5,May,2014
Government,France,Velo,1496,350.00,523600.00,31416.00,492184.00,388960.00,103224.00,6/1/2014,6,June,2014
Government,Mexico,Velo,1498,7.00,10486.00,629.16,9856.84,7490.00,2366.84,6/1/2014,6,June,2014
Small Business,France,Velo,1221,300.00,366300.00,21978.00,344322.00,305250.00,39072.00,10/1/2013,10,October,2013
Government,France,Velo,2076,350.00,726600.00,43596.00,683004.00,539760.00,143244.00,10/1/2013,10,October,2013
Midmarket,Canada,VTT,2844,15.00,42660.00,2559.60,40100.40,28440.00,11660.40,6/1/2014,6,June,2014
Government,Mexico,VTT,1498,7.00,10486.00,629.16,9856.84,7490.00,2366.84,6/1/2014,6,June,2014
Small Business,France,VTT,1221,300.00,366300.00,21978.00,344322.00,305250.00,39072.00,10/1/2013,10,October,2013
Government,Mexico,VTT,1123,20.00,22460.00,1347.60,21112.40,11230.00,9882.40,11/1/2013,11,November,2013
Small Business,Canada,VTT,2436,300.00,730800.00,43848.00,686952.00,609000.00,77952.00,12/1/2013,12,December,2013
Enterprise,France,Amarilla,1987.5,125.00,248437.50,14906.25,233531.25,238500.00,-4968.75,1/1/2014,1,January,2014
Government,Mexico,Amarilla,1679,350.00,587650.00,35259.00,552391.00,436540.00,115851.00,9/1/2014,9,September,2014
Government,United States of America,Amarilla,727,350.00,254450.00,15267.00,239183.00,189020.00,50163.00,10/1/2013,10,October,2013
Government,France,Amarilla,1403,7.00,9821.00,589.26,9231.74,7015.00,2216.74,10/1/2013,10,October,2013
Government,France,Amarilla,2076,350.00,726600.00,43596.00,683004.00,539760.00,143244.00,10/1/2013,10,October,2013
Government,France,Montana,1757,20.00,35140.00,2108.40,33031.60,17570.00,15461.60,10/1/2013,10,October,2013
Midmarket,United States of America,Paseo,2198,15.00,32970.00,1978.20,30991.80,21980.00,9011.80,8/1/2014,8,August,2014
Midmarket,Germany,Paseo,1743,15.00,26145.00,1568.70,24576.30,17430.00,7146.30,8/1/2014,8,August,2014
Midmarket,United States of America,Paseo,1153,15.00,17295.00,1037.70,16257.30,11530.00,4727.30,10/1/2014,10,October,2014
Government,France,Paseo,1757,20.00,35140.00,2108.40,33031.60,17570.00,15461.60,10/1/2013,10,October,2013
Government,Germany,Velo,1001,20.00,20020.00,1201.20,18818.80,10010.00,8808.80,8/1/2014,8,August,2014
Government,Mexico,Velo,1333,7.00,9331.00,559.86,8771.14,6665.00,2106.14,11/1/2014,11,November,2014
Midmarket,United States of America,VTT,1153,15.00,17295.00,1037.70,16257.30,11530.00,4727.30,10/1/2014,10,October,2014
Channel Partners,Mexico,Carretera,727,12.00,8724.00,610.68,8113.32,2181.00,5932.32,2/1/2014,2,February,2014
Channel Partners,Canada,Carretera,1884,12.00,22608.00,1582.56,21025.44,5652.00,15373.44,8/1/2014,8,August,2014
Government,Mexico,Carretera,1834,20.00,36680.00,2567.60,34112.40,18340.00,15772.40,9/1/2013,9,September,2013
Channel Partners,Mexico,Montana,2340,12.00,28080.00,1965.60,26114.40,7020.00,19094.40,1/1/2014,1,January,2014
Channel Partners,France,Montana,2342,12.00,28104.00,1967.28,26136.72,7026.00,19110.72,11/1/2014,11,November,2014
Government,France,Paseo,1031,7.00,7217.00,505.19,6711.81,5155.00,1556.81,9/1/2013,9,September,2013
Midmarket,Canada,Velo,1262,15.00,18930.00,1325.10,17604.90,12620.00,4984.90,5/1/2014,5,May,2014
Government,Canada,Velo,1135,7.00,7945.00,556.15,7388.85,5675.00,1713.85,6/1/2014,6,June,2014
Government,United States of America,Velo,547,7.00,3829.00,268.03,3560.97,2735.00,825.97,11/1/2014,11,November,2014
Government,Canada,Velo,1582,7.00,11074.00,775.18,10298.82,7910.00,2388.82,12/1/2014,12,December,2014
Channel Partners,France,VTT,1738.5,12.00,20862.00,1460.34,19401.66,5215.50,14186.16,4/1/2014,4,April,2014
Channel Partners,Germany,VTT,2215,12.00,26580.00,1860.60,24719.40,6645.00,18074.40,9/1/2013,9,September,2013
Government,Canada,VTT,1582,7.00,11074.00,775.18,10298.82,7910.00,2388.82,12/1/2014,12,December,2014
Government,Canada,Amarilla,1135,7.00,7945.00,556.15,7388.85,5675.00,1713.85,6/1/2014,6,June,2014
Government,United States of America,Carretera,1761,350.00,616350.00,43144.50,573205.50,457860.00,115345.50,3/1/2014,3,March,2014
Small Business,France,Carretera,448,300.00,134400.00,9408.00,124992.00,112000.00,12992.00,6/1/2014,6,June,2014
Small Business,France,Carretera,2181,300.00,654300.00,45801.00,608499.00,545250.00,63249.00,10/1/2014,10,October,2014
Government,France,Montana,1976,20.00,39520.00,2766.40,36753.60,19760.00,16993.60,10/1/2014,10,October,2014
Small Business,France,Montana,2181,300.00,654300.00,45801.00,608499.00,545250.00,63249.00,10/1/2014,10,October,2014
Enterprise,Germany,Montana,2500,125.00,312500.00,21875.00,290625.00,300000.00,-9375.00,11/1/2013,11,November,2013
Small Business,Canada,Paseo,1702,300.00,510600.00,35742.00,474858.00,425500.00,49358.00,5/1/2014,5,May,2014
Small Business,France,Paseo,448,300.00,134400.00,9408.00,124992.00,112000.00,12992.00,6/1/2014,6,June,2014
Enterprise,Germany,Paseo,3513,125.00,439125.00,30738.75,408386.25,421560.00,-13173.75,7/1/2014,7,July,2014
Midmarket,France,Paseo,2101,15.00,31515.00,2206.05,29308.95,21010.00,8298.95,8/1/2014,8,August,2014
Midmarket,United States of America,Paseo,2931,15.00,43965.00,3077.55,40887.45,29310.00,11577.45,9/1/2013,9,September,2013
Government,France,Paseo,1535,20.00,30700.00,2149.00,28551.00,15350.00,13201.00,9/1/2014,9,September,2014
Small Business,Germany,Paseo,1123,300.00,336900.00,23583.00,313317.00,280750.00,32567.00,9/1/2013,9,September,2013
Small Business,Canada,Paseo,1404,300.00,421200.00,29484.00,391716.00,351000.00,40716.00,11/1/2013,11,November,2013
Channel Partners,Mexico,Paseo,2763,12.00,33156.00,2320.92,30835.08,8289.00,22546.08,11/1/2013,11,November,2013
Government,Germany,Paseo,2125,7.00,14875.00,1041.25,13833.75,10625.00,3208.75,12/1/2013,12,December,2013
Small Business,France,Velo,1659,300.00,497700.00,34839.00,462861.00,414750.00,48111.00,7/1/2014,7,July,2014
Government,Mexico,Velo,609,20.00,12180.00,852.60,11327.40,6090.00,5237.40,8/1/2014,8,August,2014
Enterprise,Germany,Velo,2087,125.00,260875.00,18261.25,242613.75,250440.00,-7826.25,9/1/2014,9,September,2014
Government,France,Velo,1976,20.00,39520.00,2766.40,36753.60,19760.00,16993.60,10/1/2014,10,October,2014
Government,United States of America,Velo,1421,20.00,28420.00,1989.40,26430.60,14210.00,12220.60,12/1/2013,12,December,2013
Small Business,United States of America,Velo,1372,300.00,411600.00,28812.00,382788.00,343000.00,39788.00,12/1/2014,12,December,2014
Government,Germany,Velo,588,20.00,11760.00,823.20,10936.80,5880.00,5056.80,12/1/2013,12,December,2013
Channel Partners,Canada,VTT,3244.5,12.00,38934.00,2725.38,36208.62,9733.50,26475.12,1/1/2014,1,January,2014
Small Business,France,VTT,959,300.00,287700.00,20139.00,267561.00,239750.00,27811.00,2/1/2014,2,February,2014
Small Business,Mexico,VTT,2747,300.00,824100.00,57687.00,766413.00,686750.00,79663.00,2/1/2014,2,February,2014
Enterprise,Canada,Amarilla,1645,125.00,205625.00,14393.75,191231.25,197400.00,-6168.75,5/1/2014,5,May,2014
Government,France,Amarilla,2876,350.00,1006600.00,70462.00,936138.00,747760.00,188378.00,9/1/2014,9,September,2014
Enterprise,Germany,Amarilla,994,125.00,124250.00,8697.50,115552.50,119280.00,-3727.50,9/1/2013,9,September,2013
Government,Canada,Amarilla,1118,20.00,22360.00,1565.20,20794.80,11180.00,9614.80,11/1/2014,11,November,2014
Small Business,United States of America,Amarilla,1372,300.00,411600.00,28812.00,382788.00,343000.00,39788.00,12/1/2014,12,December,2014
Government,Canada,Montana,488,7.00,3416.00,273.28,3142.72,2440.00,702.72,2/1/2014,2,February,2014
Government,United States of America,Montana,1282,20.00,25640.00,2051.20,23588.80,12820.00,10768.80,6/1/2014,6,June,2014
Government,Canada,Paseo,257,7.00,1799.00,143.92,1655.08,1285.00,370.08,5/1/2014,5,May,2014
Government,United States of America,Amarilla,1282,20.00,25640.00,2051.20,23588.80,12820.00,10768.80,6/1/2014,6,June,2014
Enterprise,Mexico,Carretera,1540,125.00,192500.00,15400.00,177100.00,184800.00,-7700.00,8/1/2014,8,August,2014
Midmarket,France,Carretera,490,15.00,7350.00,588.00,6762.00,4900.00,1862.00,11/1/2014,11,November,2014
Government,Mexico,Carretera,1362,350.00,476700.00,38136.00,438564.00,354120.00,84444.00,12/1/2014,12,December,2014
Midmarket,France,Montana,2501,15.00,37515.00,3001.20,34513.80,25010.00,9503.80,3/1/2014,3,March,2014
Government,Canada,Montana,708,20.00,14160.00,1132.80,13027.20,7080.00,5947.20,6/1/2014,6,June,2014
Government,Germany,Montana,645,20.00,12900.00,1032.00,11868.00,6450.00,5418.00,7/1/2014,7,July,2014
Small Business,France,Montana,1562,300.00,468600.00,37488.00,431112.00,390500.00,40612.00,8/1/2014,8,August,2014
Small Business,Canada,Montana,1283,300.00,384900.00,30792.00,354108.00,320750.00,33358.00,9/1/2013,9,September,2013
Midmarket,Germany,Montana,711,15.00,10665.00,853.20,9811.80,7110.00,2701.80,12/1/2014,12,December,2014
Enterprise,Mexico,Paseo,1114,125.00,139250.00,11140.00,128110.00,133680.00,-5570.00,3/1/2014,3,March,2014
Government,Germany,Paseo,1259,7.00,8813.00,705.04,8107.96,6295.00,1812.96,4/1/2014,4,April,2014
Government,Germany,Paseo,1095,7.00,7665.00,613.20,7051.80,5475.00,1576.80,5/1/2014,5,May,2014
Government,Germany,Paseo,1366,20.00,27320.00,2185.60,25134.40,13660.00,11474.40,6/1/2014,6,June,2014
Small Business,Mexico,Paseo,2460,300.00,738000.00,59040.00,678960.00,615000.00,63960.00,6/1/2014,6,June,2014
Government,United States of America,Paseo,678,7.00,4746.00,379.68,4366.32,3390.00,976.32,8/1/2014,8,August,2014
Government,Germany,Paseo,1598,7.00,11186.00,894.88,10291.12,7990.00,2301.12,8/1/2014,8,August,2014
Government,Germany,Paseo,2409,7.00,16863.00,1349.04,15513.96,12045.00,3468.96,9/1/2013,9,September,2013
Government,Germany,Paseo,1934,20.00,38680.00,3094.40,35585.60,19340.00,16245.60,9/1/2014,9,September,2014
Government,Mexico,Paseo,2993,20.00,59860.00,4788.80,55071.20,29930.00,25141.20,9/1/2014,9,September,2014
Government,Germany,Paseo,2146,350.00,751100.00,60088.00,691012.00,557960.00,133052.00,11/1/2013,11,November,2013
Government,Mexico,Paseo,1946,7.00,13622.00,1089.76,12532.24,9730.00,2802.24,12/1/2013,12,December,2013
Government,Mexico,Paseo,1362,350.00,476700.00,38136.00,438564.00,354120.00,84444.00,12/1/2014,12,December,2014
Channel Partners,Canada,Velo,598,12.00,7176.00,574.08,6601.92,1794.00,4807.92,3/1/2014,3,March,2014
Government,United States of America,Velo,2907,7.00,20349.00,1627.92,18721.08,14535.00,4186.08,6/1/2014,6,June,2014
Government,Germany,Velo,2338,7.00,16366.00,1309.28,15056.72,11690.00,3366.72,6/1/2014,6,June,2014
Small Business,France,Velo,386,300.00,115800.00,9264.00,106536.00,96500.00,10036.00,11/1/2013,11,November,2013
Small Business,Mexico,Velo,635,300.00,190500.00,15240.00,175260.00,158750.00,16510.00,12/1/2014,12,December,2014
Government,France,VTT,574.5,350.00,201075.00,16086.00,184989.00,149370.00,35619.00,4/1/2014,4,April,2014
Government,Germany,VTT,2338,7.00,16366.00,1309.28,15056.72,11690.00,3366.72,6/1/2014,6,June,2014
Government,France,VTT,381,350.00,133350.00,10668.00,122682.00,99060.00,23622.00,8/1/2014,8,August,2014
Government,Germany,VTT,422,350.00,147700.00,11816.00,135884.00,109720.00,26164.00,8/1/2014,8,August,2014
Small Business,Canada,VTT,2134,300.00,640200.00,51216.00,588984.00,533500.00,55484.00,9/1/2014,9,September,2014
Small Business,United States of America,VTT,808,300.00,242400.00,19392.00,223008.00,202000.00,21008.00,12/1/2013,12,December,2013
Government,Canada,Amarilla,708,20.00,14160.00,1132.80,13027.20,7080.00,5947.20,6/1/2014,6,June,2014
Government,United States of America,Amarilla,2907,7.00,20349.00,1627.92,18721.08,14535.00,4186.08,6/1/2014,6,June,2014
Government,Germany,Amarilla,1366,20.00,27320.00,2185.60,25134.40,13660.00,11474.40,6/1/2014,6,June,2014
Small Business,Mexico,Amarilla,2460,300.00,738000.00,59040.00,678960.00,615000.00,63960.00,6/1/2014,6,June,2014
Government,Germany,Amarilla,1520,20.00,30400.00,2432.00,27968.00,15200.00,12768.00,11/1/2014,11,November,2014
Midmarket,Germany,Amarilla,711,15.00,10665.00,853.20,9811.80,7110.00,2701.80,12/1/2014,12,December,2014
Channel Partners,Mexico,Amarilla,1375,12.00,16500.00,1320.00,15180.00,4125.00,11055.00,12/1/2013,12,December,2013
Small Business,Mexico,Amarilla,635,300.00,190500.00,15240.00,175260.00,158750.00,16510.00,12/1/2014,12,December,2014
Government,United States of America,VTT,436.5,20.00,8730.00,698.40,8031.60,4365.00,3666.60,7/1/2014,7,July,2014
Small Business,Canada,Carretera,1094,300.00,328200.00,29538.00,298662.00,273500.00,25162.00,6/1/2014,6,June,2014
Channel Partners,Mexico,Carretera,367,12.00,4404.00,396.36,4007.64,1101.00,2906.64,10/1/2013,10,October,2013
Small Business,Canada,Montana,3802.5,300.00,1140750.00,102667.50,1038082.50,950625.00,87457.50,4/1/2014,4,April,2014
Government,France,Montana,1666,350.00,583100.00,52479.00,530621.00,433160.00,97461.00,5/1/2014,5,May,2014
Small Business,France,Montana,322,300.00,96600.00,8694.00,87906.00,80500.00,7406.00,9/1/2013,9,September,2013
Channel Partners,Canada,Montana,2321,12.00,27852.00,2506.68,25345.32,6963.00,18382.32,11/1/2014,11,November,2014
Enterprise,France,Montana,1857,125.00,232125.00,20891.25,211233.75,222840.00,-11606.25,11/1/2013,11,November,2013
Government,Canada,Montana,1611,7.00,11277.00,1014.93,10262.07,8055.00,2207.07,12/1/2013,12,December,2013
Enterprise,United States of America,Montana,2797,125.00,349625.00,31466.25,318158.75,335640.00,-17481.25,12/1/2014,12,December,2014
Small Business,Germany,Montana,334,300.00,100200.00,9018.00,91182.00,83500.00,7682.00,12/1/2013,12,December,2013
Small Business,Mexico,Paseo,2565,300.00,769500.00,69255.00,700245.00,641250.00,58995.00,1/1/2014,1,January,2014
Government,Mexico,Paseo,2417,350.00,845950.00,76135.50,769814.50,628420.00,141394.50,1/1/2014,1,January,2014
Midmarket,United States of America,Paseo,3675,15.00,55125.00,4961.25,50163.75,36750.00,13413.75,4/1/2014,4,April,2014
Small Business,Canada,Paseo,1094,300.00,328200.00,29538.00,298662.00,273500.00,25162.00,6/1/2014,6,June,2014
Midmarket,France,Paseo,1227,15.00,18405.00,1656.45,16748.55,12270.00,4478.55,10/1/2014,10,October,2014
Channel Partners,Mexico,Paseo,367,12.00,4404.00,396.36,4007.64,1101.00,2906.64,10/1/2013,10,October,2013
Small Business,France,Paseo,1324,300.00,397200.00,35748.00,361452.00,331000.00,30452.00,11/1/2014,11,November,2014
Channel Partners,Germany,Paseo,1775,12.00,21300.00,1917.00,19383.00,5325.00,14058.00,11/1/2013,11,November,2013
Enterprise,United States of America,Paseo,2797,125.00,349625.00,31466.25,318158.75,335640.00,-17481.25,12/1/2014,12,December,2014
Midmarket,Mexico,Velo,245,15.00,3675.00,330.75,3344.25,2450.00,894.25,5/1/2014,5,May,2014
Small Business,Canada,Velo,3793.5,300.00,1138050.00,102424.50,1035625.50,948375.00,87250.50,7/1/2014,7,July,2014
Government,Germany,Velo,1307,350.00,457450.00,41170.50,416279.50,339820.00,76459.50,7/1/2014,7,July,2014
Enterprise,Canada,Velo,567,125.00,70875.00,6378.75,64496.25,68040.00,-3543.75,9/1/2014,9,September,2014
Enterprise,Mexico,Velo,2110,125.00,263750.00,23737.50,240012.50,253200.00,-13187.50,9/1/2014,9,September,2014
Government,Canada,Velo,1269,350.00,444150.00,39973.50,404176.50,329940.00,74236.50,10/1/2014,10,October,2014
Channel Partners,United States of America,VTT,1956,12.00,23472.00,2112.48,21359.52,5868.00,15491.52,1/1/2014,1,January,2014
Small Business,Germany,VTT,2659,300.00,797700.00,71793.00,725907.00,664750.00,61157.00,2/1/2014,2,February,2014
Government,United States of America,VTT,1351.5,350.00,473025.00,42572.25,430452.75,351390.00,79062.75,4/1/2014,4,April,2014
Channel Partners,Germany,VTT,880,12.00,10560.00,950.40,9609.60,2640.00,6969.60,5/1/2014,5,May,2014
Small Business,United States of America,VTT,1867,300.00,560100.00,50409.00,509691.00,466750.00,42941.00,9/1/2014,9,September,2014
Channel Partners,France,VTT,2234,12.00,26808.00,2412.72,24395.28,6702.00,17693.28,9/1/2013,9,September,2013
Midmarket,France,VTT,1227,15.00,18405.00,1656.45,16748.55,12270.00,4478.55,10/1/2014,10,October,2014
Enterprise,Mexico,VTT,877,125.00,109625.00,9866.25,99758.75,105240.00,-5481.25,11/1/2014,11,November,2014
Government,United States of America,Amarilla,2071,350.00,724850.00,65236.50,659613.50,538460.00,121153.50,9/1/2014,9,September,2014
Government,Canada,Amarilla,1269,350.00,444150.00,39973.50,404176.50,329940.00,74236.50,10/1/2014,10,October,2014
Midmarket,Germany,Amarilla,970,15.00,14550.00,1309.50,13240.50,9700.00,3540.50,11/1/2013,11,November,2013
Government,Mexico,Amarilla,1694,20.00,33880.00,3049.20,30830.80,16940.00,13890.80,11/1/2014,11,November,2014
Government,Germany,Carretera,663,20.00,13260.00,1193.40,12066.60,6630.00,5436.60,5/1/2014,5,May,2014
Government,Canada,Carretera,819,7.00,5733.00,515.97,5217.03,4095.00,1122.03,7/1/2014,7,July,2014
Channel Partners,Germany,Carretera,1580,12.00,18960.00,1706.40,17253.60,4740.00,12513.60,9/1/2014,9,September,2014
Government,Mexico,Carretera,521,7.00,3647.00,328.23,3318.77,2605.00,713.77,12/1/2014,12,December,2014
Government,United States of America,Paseo,973,20.00,19460.00,1751.40,17708.60,9730.00,7978.60,3/1/2014,3,March,2014
Government,Mexico,Paseo,1038,20.00,20760.00,1868.40,18891.60,10380.00,8511.60,6/1/2014,6,June,2014
Government,Germany,Paseo,360,7.00,2520.00,226.80,2293.20,1800.00,493.20,10/1/2014,10,October,2014
Channel Partners,France,Velo,1967,12.00,23604.00,2124.36,21479.64,5901.00,15578.64,3/1/2014,3,March,2014
Midmarket,Mexico,Velo,2628,15.00,39420.00,3547.80,35872.20,26280.00,9592.20,4/1/2014,4,April,2014
Government,Germany,VTT,360,7.00,2520.00,226.80,2293.20,1800.00,493.20,10/1/2014,10,October,2014
Government,France,VTT,2682,20.00,53640.00,4827.60,48812.40,26820.00,21992.40,11/1/2013,11,November,2013
Government,Mexico,VTT,521,7.00,3647.00,328.23,3318.77,2605.00,713.77,12/1/2014,12,December,2014
Government,Mexico,Amarilla,1038,20.00,20760.00,1868.40,18891.60,10380.00,8511.60,6/1/2014,6,June,2014
Midmarket,Canada,Amarilla,1630.5,15.00,24457.50,2201.18,22256.33,16305.00,5951.33,7/1/2014,7,July,2014
Channel Partners,France,Amarilla,306,12.00,3672.00,330.48,3341.52,918.00,2423.52,12/1/2013,12,December,2013
Channel Partners,United States of America,Carretera,386,12.00,4632.00,463.20,4168.80,1158.00,3010.80,10/1/2013,10,October,2013
Government,United States of America,Montana,2328,7.00,16296.00,1629.60,14666.40,11640.00,3026.40,9/1/2014,9,September,2014
Channel Partners,United States of America,Paseo,386,12.00,4632.00,463.20,4168.80,1158.00,3010.80,10/1/2013,10,October,2013
Enterprise,United States of America,Carretera,3445.5,125.00,430687.50,43068.75,387618.75,413460.00,-25841.25,4/1/2014,4,April,2014
Enterprise,France,Carretera,1482,125.00,185250.00,18525.00,166725.00,177840.00,-11115.00,12/1/2013,12,December,2013
Government,United States of America,Montana,2313,350.00,809550.00,80955.00,728595.00,601380.00,127215.00,5/1/2014,5,May,2014
Enterprise,United States of America,Montana,1804,125.00,225500.00,22550.00,202950.00,216480.00,-13530.00,11/1/2013,11,November,2013
Midmarket,France,Montana,2072,15.00,31080.00,3108.00,27972.00,20720.00,7252.00,12/1/2014,12,December,2014
Government,France,Paseo,1954,20.00,39080.00,3908.00,35172.00,19540.00,15632.00,3/1/2014,3,March,2014
Small Business,Mexico,Paseo,591,300.00,177300.00,17730.00,159570.00,147750.00,11820.00,5/1/2014,5,May,2014
Midmarket,France,Paseo,2167,15.00,32505.00,3250.50,29254.50,21670.00,7584.50,10/1/2013,10,October,2013
Government,Germany,Paseo,241,20.00,4820.00,482.00,4338.00,2410.00,1928.00,10/1/2014,10,October,2014
Midmarket,Germany,Velo,681,15.00,10215.00,1021.50,9193.50,6810.00,2383.50,1/1/2014,1,January,2014
Midmarket,Germany,Velo,510,15.00,7650.00,765.00,6885.00,5100.00,1785.00,4/1/2014,4,April,2014
Midmarket,United States of America,Velo,790,15.00,11850.00,1185.00,10665.00,7900.00,2765.00,5/1/2014,5,May,2014
Government,France,Velo,639,350.00,223650.00,22365.00,201285.00,166140.00,35145.00,7/1/2014,7,July,2014
Enterprise,United States of America,Velo,1596,125.00,199500.00,19950.00,179550.00,191520.00,-11970.00,9/1/2014,9,September,2014
Small Business,United States of America,Velo,2294,300.00,688200.00,68820.00,619380.00,573500.00,45880.00,10/1/2013,10,October,2013
Government,Germany,Velo,241,20.00,4820.00,482.00,4338.00,2410.00,1928.00,10/1/2014,10,October,2014
Government,Germany,Velo,2665,7.00,18655.00,1865.50,16789.50,13325.00,3464.50,11/1/2014,11,November,2014
Enterprise,Canada,Velo,1916,125.00,239500.00,23950.00,215550.00,229920.00,-14370.00,12/1/2013,12,December,2013
Small Business,France,Velo,853,300.00,255900.00,25590.00,230310.00,213250.00,17060.00,12/1/2014,12,December,2014
Enterprise,Mexico,VTT,341,125.00,42625.00,4262.50,38362.50,40920.00,-2557.50,5/1/2014,5,May,2014
Midmarket,Mexico,VTT,641,15.00,9615.00,961.50,8653.50,6410.00,2243.50,7/1/2014,7,July,2014
Government,United States of America,VTT,2807,350.00,982450.00,98245.00,884205.00,729820.00,154385.00,8/1/2014,8,August,2014
Small Business,Mexico,VTT,432,300.00,129600.00,12960.00,116640.00,108000.00,8640.00,9/1/2014,9,September,2014
Small Business,United States of America,VTT,2294,300.00,688200.00,68820.00,619380.00,573500.00,45880.00,10/1/2013,10,October,2013
Midmarket,France,VTT,2167,15.00,32505.00,3250.50,29254.50,21670.00,7584.50,10/1/2013,10,October,2013
Enterprise,Canada,VTT,2529,125.00,316125.00,31612.50,284512.50,303480.00,-18967.50,11/1/2014,11,November,2014
Government,Germany,VTT,1870,350.00,654500.00,65450.00,589050.00,486200.00,102850.00,12/1/2013,12,December,2013
Enterprise,United States of America,Amarilla,579,125.00,72375.00,7237.50,65137.50,69480.00,-4342.50,1/1/2014,1,January,2014
Government,Canada,Amarilla,2240,350.00,784000.00,78400.00,705600.00,582400.00,123200.00,2/1/2014,2,February,2014
Small Business,United States of America,Amarilla,2993,300.00,897900.00,89790.00,808110.00,748250.00,59860.00,3/1/2014,3,March,2014
Channel Partners,Canada,Amarilla,3520.5,12.00,42246.00,4224.60,38021.40,10561.50,27459.90,4/1/2014,4,April,2014
Government,Mexico,Amarilla,2039,20.00,40780.00,4078.00,36702.00,20390.00,16312.00,5/1/2014,5,May,2014
Channel Partners,Germany,Amarilla,2574,12.00,30888.00,3088.80,27799.20,7722.00,20077.20,8/1/2014,8,August,2014
Government,Canada,Amarilla,707,350.00,247450.00,24745.00,222705.00,183820.00,38885.00,9/1/2014,9,September,2014
Midmarket,France,Amarilla,2072,15.00,31080.00,3108.00,27972.00,20720.00,7252.00,12/1/2014,12,December,2014
Small Business,France,Amarilla,853,300.00,255900.00,25590.00,230310.00,213250.00,17060.00,12/1/2014,12,December,2014
Channel Partners,France,Carretera,1198,12.00,14376.00,1581.36,12794.64,3594.00,9200.64,10/1/2013,10,October,2013
Government,France,Paseo,2532,7.00,17724.00,1949.64,15774.36,12660.00,3114.36,4/1/2014,4,April,2014
Channel Partners,France,Paseo,1198,12.00,14376.00,1581.36,12794.64,3594.00,9200.64,10/1/2013,10,October,2013
Midmarket,Canada,Velo,384,15.00,5760.00,633.60,5126.40,3840.00,1286.40,1/1/2014,1,January,2014
Channel Partners,Germany,Velo,472,12.00,5664.00,623.04,5040.96,1416.00,3624.96,10/1/2014,10,October,2014
Government,United States of America,VTT,1579,7.00,11053.00,1215.83,9837.17,7895.00,1942.17,3/1/2014,3,March,2014
Channel Partners,Mexico,VTT,1005,12.00,12060.00,1326.60,10733.40,3015.00,7718.40,9/1/2013,9,September,2013
Midmarket,United States of America,Amarilla,3199.5,15.00,47992.50,5279.18,42713.33,31995.00,10718.33,7/1/2014,7,July,2014
Channel Partners,Germany,Amarilla,472,12.00,5664.00,623.04,5040.96,1416.00,3624.96,10/1/2014,10,October,2014
Channel Partners,Canada,Carretera,1937,12.00,23244.00,2556.84,20687.16,5811.00,14876.16,2/1/2014,2,February,2014
Government,Germany,Carretera,792,350.00,277200.00,30492.00,246708.00,205920.00,40788.00,3/1/2014,3,March,2014
Small Business,Germany,Carretera,2811,300.00,843300.00,92763.00,750537.00,702750.00,47787.00,7/1/2014,7,July,2014
Enterprise,France,Carretera,2441,125.00,305125.00,33563.75,271561.25,292920.00,-21358.75,10/1/2014,10,October,2014
Midmarket,Canada,Carretera,1560,15.00,23400.00,2574.00,20826.00,15600.00,5226.00,11/1/2013,11,November,2013
Government,Mexico,Carretera,2706,7.00,18942.00,2083.62,16858.38,13530.00,3328.38,11/1/2013,11,November,2013
Government,Germany,Montana,766,350.00,268100.00,29491.00,238609.00,199160.00,39449.00,1/1/2014,1,January,2014
Government,Germany,Montana,2992,20.00,59840.00,6582.40,53257.60,29920.00,23337.60,10/1/2013,10,October,2013
Midmarket,Mexico,Montana,2157,15.00,32355.00,3559.05,28795.95,21570.00,7225.95,12/1/2014,12,December,2014
Small Business,Canada,Paseo,873,300.00,261900.00,28809.00,233091.00,218250.00,14841.00,1/1/2014,1,January,2014
Government,Mexico,Paseo,1122,20.00,22440.00,2468.40,19971.60,11220.00,8751.60,3/1/2014,3,March,2014
Government,Canada,Paseo,2104.5,350.00,736575.00,81023.25,655551.75,547170.00,108381.75,7/1/2014,7,July,2014
Channel Partners,Canada,Paseo,4026,12.00,48312.00,5314.32,42997.68,12078.00,30919.68,7/1/2014,7,July,2014
Channel Partners,France,Paseo,2425.5,12.00,29106.00,3201.66,25904.34,7276.50,18627.84,7/1/2014,7,July,2014
Government,Canada,Paseo,2394,20.00,47880.00,5266.80,42613.20,23940.00,18673.20,8/1/2014,8,August,2014
Midmarket,Mexico,Paseo,1984,15.00,29760.00,3273.60,26486.40,19840.00,6646.40,8/1/2014,8,August,2014
Enterprise,France,Paseo,2441,125.00,305125.00,33563.75,271561.25,292920.00,-21358.75,10/1/2014,10,October,2014
Government,Germany,Paseo,2992,20.00,59840.00,6582.40,53257.60,29920.00,23337.60,10/1/2013,10,October,2013
Small Business,Canada,Paseo,1366,300.00,409800.00,45078.00,364722.00,341500.00,23222.00,11/1/2014,11,November,2014
Government,France,Velo,2805,20.00,56100.00,6171.00,49929.00,28050.00,21879.00,9/1/2013,9,September,2013
Midmarket,Mexico,Velo,655,15.00,9825.00,1080.75,8744.25,6550.00,2194.25,9/1/2013,9,September,2013
Government,Mexico,Velo,344,350.00,120400.00,13244.00,107156.00,89440.00,17716.00,10/1/2013,10,October,2013
Government,Canada,Velo,1808,7.00,12656.00,1392.16,11263.84,9040.00,2223.84,11/1/2014,11,November,2014
Channel Partners,France,VTT,1734,12.00,20808.00,2288.88,18519.12,5202.00,13317.12,1/1/2014,1,January,2014
Enterprise,Mexico,VTT,554,125.00,69250.00,7617.50,61632.50,66480.00,-4847.50,1/1/2014,1,January,2014
Government,Canada,VTT,2935,20.00,58700.00,6457.00,52243.00,29350.00,22893.00,11/1/2013,11,November,2013
Enterprise,Germany,Amarilla,3165,125.00,395625.00,43518.75,352106.25,379800.00,-27693.75,1/1/2014,1,January,2014
Government,Mexico,Amarilla,2629,20.00,52580.00,5783.80,46796.20,26290.00,20506.20,1/1/2014,1,January,2014
Enterprise,France,Amarilla,1433,125.00,179125.00,19703.75,159421.25,171960.00,-12538.75,5/1/2014,5,May,2014
Enterprise,Mexico,Amarilla,947,125.00,118375.00,13021.25,105353.75,113640.00,-8286.25,9/1/2013,9,September,2013
Government,Mexico,Amarilla,344,350.00,120400.00,13244.00,107156.00,89440.00,17716.00,10/1/2013,10,October,2013
Midmarket,Mexico,Amarilla,2157,15.00,32355.00,3559.05,28795.95,21570.00,7225.95,12/1/2014,12,December,2014
Government,United States of America,Paseo,380,7.00,2660.00,292.60,2367.40,1900.00,467.40,9/1/2013,9,September,2013
Government,Mexico,Carretera,886,350.00,310100.00,37212.00,272888.00,230360.00,42528.00,6/1/2014,6,June,2014
Enterprise,Canada,Carretera,2416,125.00,302000.00,36240.00,265760.00,289920.00,-24160.00,9/1/2013,9,September,2013
Enterprise,Mexico,Carretera,2156,125.00,269500.00,32340.00,237160.00,258720.00,-21560.00,10/1/2014,10,October,2014
Midmarket,Canada,Carretera,2689,15.00,40335.00,4840.20,35494.80,26890.00,8604.80,11/1/2014,11,November,2014
Midmarket,United States of America,Montana,677,15.00,10155.00,1218.60,8936.40,6770.00,2166.40,3/1/2014,3,March,2014
Small Business,France,Montana,1773,300.00,531900.00,63828.00,468072.00,443250.00,24822.00,4/1/2014,4,April,2014
Government,Mexico,Montana,2420,7.00,16940.00,2032.80,14907.20,12100.00,2807.20,9/1/2014,9,September,2014
Government,Canada,Montana,2734,7.00,19138.00,2296.56,16841.44,13670.00,3171.44,10/1/2014,10,October,2014
Government,Mexico,Montana,1715,20.00,34300.00,4116.00,30184.00,17150.00,13034.00,10/1/2013,10,October,2013
Small Business,France,Montana,1186,300.00,355800.00,42696.00,313104.00,296500.00,16604.00,12/1/2013,12,December,2013
Small Business,United States of America,Paseo,3495,300.00,1048500.00,125820.00,922680.00,873750.00,48930.00,1/1/2014,1,January,2014
Government,Mexico,Paseo,886,350.00,310100.00,37212.00,272888.00,230360.00,42528.00,6/1/2014,6,June,2014
Enterprise,Mexico,Paseo,2156,125.00,269500.00,32340.00,237160.00,258720.00,-21560.00,10/1/2014,10,October,2014
Government,Mexico,Paseo,905,20.00,18100.00,2172.00,15928.00,9050.00,6878.00,10/1/2014,10,October,2014
Government,Mexico,Paseo,1715,20.00,34300.00,4116.00,30184.00,17150.00,13034.00,10/1/2013,10,October,2013
Government,France,Paseo,1594,350.00,557900.00,66948.00,490952.00,414440.00,76512.00,11/1/2014,11,November,2014
Small Business,Germany,Paseo,1359,300.00,407700.00,48924.00,358776.00,339750.00,19026.00,11/1/2014,11,November,2014
Small Business,Mexico,Paseo,2150,300.00,645000.00,77400.00,567600.00,537500.00,30100.00,11/1/2014,11,November,2014
Government,Mexico,Paseo,1197,350.00,418950.00,50274.00,368676.00,311220.00,57456.00,11/1/2014,11,November,2014
Midmarket,Mexico,Paseo,380,15.00,5700.00,684.00,5016.00,3800.00,1216.00,12/1/2013,12,December,2013
Government,Mexico,Paseo,1233,20.00,24660.00,2959.20,21700.80,12330.00,9370.80,12/1/2014,12,December,2014
Government,Mexico,Velo,1395,350.00,488250.00,58590.00,429660.00,362700.00,66960.00,7/1/2014,7,July,2014
Government,United States of America,Velo,986,350.00,345100.00,41412.00,303688.00,256360.00,47328.00,10/1/2014,10,October,2014
Government,Mexico,Velo,905,20.00,18100.00,2172.00,15928.00,9050.00,6878.00,10/1/2014,10,October,2014
Channel Partners,Canada,VTT,2109,12.00,25308.00,3036.96,22271.04,6327.00,15944.04,5/1/2014,5,May,2014
Midmarket,France,VTT,3874.5,15.00,58117.50,6974.10,51143.40,38745.00,12398.40,7/1/2014,7,July,2014
Government,Canada,VTT,623,350.00,218050.00,26166.00,191884.00,161980.00,29904.00,9/1/2013,9,September,2013
Government,United States of America,VTT,986,350.00,345100.00,41412.00,303688.00,256360.00,47328.00,10/1/2014,10,October,2014
Enterprise,United States of America,VTT,2387,125.00,298375.00,35805.00,262570.00,286440.00,-23870.00,11/1/2014,11,November,2014
Government,Mexico,VTT,1233,20.00,24660.00,2959.20,21700.80,12330.00,9370.80,12/1/2014,12,December,2014
Government,United States of America,Amarilla,270,350.00,94500.00,11340.00,83160.00,70200.00,12960.00,2/1/2014,2,February,2014
Government,France,Amarilla,3421.5,7.00,23950.50,2874.06,21076.44,17107.50,3968.94,7/1/2014,7,July,2014
Government,Canada,Amarilla,2734,7.00,19138.00,2296.56,16841.44,13670.00,3171.44,10/1/2014,10,October,2014
Midmarket,United States of America,Amarilla,2548,15.00,38220.00,4586.40,33633.60,25480.00,8153.60,11/1/2013,11,November,2013
Government,France,Carretera,2521.5,20.00,50430.00,6051.60,44378.40,25215.00,19163.40,1/1/2014,1,January,2014
Channel Partners,Mexico,Montana,2661,12.00,31932.00,3831.84,28100.16,7983.00,20117.16,5/1/2014,5,May,2014
Government,Germany,Paseo,1531,20.00,30620.00,3674.40,26945.60,15310.00,11635.60,12/1/2014,12,December,2014
Government,France,VTT,1491,7.00,10437.00,1252.44,9184.56,7455.00,1729.56,3/1/2014,3,March,2014
Government,Germany,VTT,1531,20.00,30620.00,3674.40,26945.60,15310.00,11635.60,12/1/2014,12,December,2014
Channel Partners,Canada,Amarilla,2761,12.00,33132.00,3975.84,29156.16,8283.00,20873.16,9/1/2013,9,September,2013
Midmarket,United States of America,Carretera,2567,15.00,38505.00,5005.65,33499.35,25670.00,7829.35,6/1/2014,6,June,2014
Midmarket,United States of America,VTT,2567,15.00,38505.00,5005.65,33499.35,25670.00,7829.35,6/1/2014,6,June,2014
Government,Canada,Carretera,923,350.00,323050.00,41996.50,281053.50,239980.00,41073.50,3/1/2014,3,March,2014
Government,France,Carretera,1790,350.00,626500.00,81445.00,545055.00,465400.00,79655.00,3/1/2014,3,March,2014
Government,Germany,Carretera,442,20.00,8840.00,1149.20,7690.80,4420.00,3270.80,9/1/2013,9,September,2013
Government,United States of America,Montana,982.5,350.00,343875.00,44703.75,299171.25,255450.00,43721.25,1/1/2014,1,January,2014
Government,United States of America,Montana,1298,7.00,9086.00,1181.18,7904.82,6490.00,1414.82,2/1/2014,2,February,2014
Channel Partners,Mexico,Montana,604,12.00,7248.00,942.24,6305.76,1812.00,4493.76,6/1/2014,6,June,2014
Government,Mexico,Montana,2255,20.00,45100.00,5863.00,39237.00,22550.00,16687.00,7/1/2014,7,July,2014
Government,Canada,Montana,1249,20.00,24980.00,3247.40,21732.60,12490.00,9242.60,10/1/2014,10,October,2014
Government,United States of America,Paseo,1438.5,7.00,10069.50,1309.04,8760.47,7192.50,1567.97,1/1/2014,1,January,2014
Small Business,Germany,Paseo,807,300.00,242100.00,31473.00,210627.00,201750.00,8877.00,1/1/2014,1,January,2014
Government,United States of America,Paseo,2641,20.00,52820.00,6866.60,45953.40,26410.00,19543.40,2/1/2014,2,February,2014
Government,Germany,Paseo,2708,20.00,54160.00,7040.80,47119.20,27080.00,20039.20,2/1/2014,2,February,2014
Government,Canada,Paseo,2632,350.00,921200.00,119756.00,801444.00,684320.00,117124.00,6/1/2014,6,June,2014
Enterprise,Canada,Paseo,1583,125.00,197875.00,25723.75,172151.25,189960.00,-17808.75,6/1/2014,6,June,2014
Channel Partners,Mexico,Paseo,571,12.00,6852.00,890.76,5961.24,1713.00,4248.24,7/1/2014,7,July,2014
Government,France,Paseo,2696,7.00,18872.00,2453.36,16418.64,13480.00,2938.64,8/1/2014,8,August,2014
Midmarket,Canada,Paseo,1565,15.00,23475.00,3051.75,20423.25,15650.00,4773.25,10/1/2014,10,October,2014
Government,Canada,Paseo,1249,20.00,24980.00,3247.40,21732.60,12490.00,9242.60,10/1/2014,10,October,2014
Government,Germany,Paseo,357,350.00,124950.00,16243.50,108706.50,92820.00,15886.50,11/1/2014,11,November,2014
Channel Partners,Germany,Paseo,1013,12.00,12156.00,1580.28,10575.72,3039.00,7536.72,12/1/2014,12,December,2014
Midmarket,France,Velo,3997.5,15.00,59962.50,7795.13,52167.38,39975.00,12192.38,1/1/2014,1,January,2014
Government,Canada,Velo,2632,350.00,921200.00,119756.00,801444.00,684320.00,117124.00,6/1/2014,6,June,2014
Government,France,Velo,1190,7.00,8330.00,1082.90,7247.10,5950.00,1297.10,6/1/2014,6,June,2014
Channel Partners,Mexico,Velo,604,12.00,7248.00,942.24,6305.76,1812.00,4493.76,6/1/2014,6,June,2014
Midmarket,Germany,Velo,660,15.00,9900.00,1287.00,8613.00,6600.00,2013.00,9/1/2013,9,September,2013
Channel Partners,Mexico,Velo,410,12.00,4920.00,639.60,4280.40,1230.00,3050.40,10/1/2014,10,October,2014
Small Business,Mexico,Velo,2605,300.00,781500.00,101595.00,679905.00,651250.00,28655.00,11/1/2013,11,November,2013
Channel Partners,Germany,Velo,1013,12.00,12156.00,1580.28,10575.72,3039.00,7536.72,12/1/2014,12,December,2014
Enterprise,Canada,VTT,1583,125.00,197875.00,25723.75,172151.25,189960.00,-17808.75,6/1/2014,6,June,2014
Midmarket,Canada,VTT,1565,15.00,23475.00,3051.75,20423.25,15650.00,4773.25,10/1/2014,10,October,2014
Enterprise,Canada,Amarilla,1659,125.00,207375.00,26958.75,180416.25,199080.00,-18663.75,1/1/2014,1,January,2014
Government,France,Amarilla,1190,7.00,8330.00,1082.90,7247.10,5950.00,1297.10,6/1/2014,6,June,2014
Channel Partners,Mexico,Amarilla,410,12.00,4920.00,639.60,4280.40,1230.00,3050.40,10/1/2014,10,October,2014
Channel Partners,Germany,Amarilla,1770,12.00,21240.00,2761.20,18478.80,5310.00,13168.80,12/1/2013,12,December,2013
Government,Mexico,Carretera,2579,20.00,51580.00,7221.20,44358.80,25790.00,18568.80,4/1/2014,4,April,2014
Government,United States of America,Carretera,1743,20.00,34860.00,4880.40,29979.60,17430.00,12549.60,5/1/2014,5,May,2014
Government,United States of America,Carretera,2996,7.00,20972.00,2936.08,18035.92,14980.00,3055.92,10/1/2013,10,October,2013
Government,Germany,Carretera,280,7.00,1960.00,274.40,1685.60,1400.00,285.60,12/1/2014,12,December,2014
Government,France,Montana,293,7.00,2051.00,287.14,1763.86,1465.00,298.86,2/1/2014,2,February,2014
Government,United States of America,Montana,2996,7.00,20972.00,2936.08,18035.92,14980.00,3055.92,10/1/2013,10,October,2013
Midmarket,Germany,Paseo,278,15.00,4170.00,583.80,3586.20,2780.00,806.20,2/1/2014,2,February,2014
Government,Canada,Paseo,2428,20.00,48560.00,6798.40,41761.60,24280.00,17481.60,3/1/2014,3,March,2014
Midmarket,United States of America,Paseo,1767,15.00,26505.00,3710.70,22794.30,17670.00,5124.30,9/1/2014,9,September,2014
Channel Partners,France,Paseo,1393,12.00,16716.00,2340.24,14375.76,4179.00,10196.76,10/1/2014,10,October,2014
Government,Germany,VTT,280,7.00,1960.00,274.40,1685.60,1400.00,285.60,12/1/2014,12,December,2014
Channel Partners,France,Amarilla,1393,12.00,16716.00,2340.24,14375.76,4179.00,10196.76,10/1/2014,10,October,2014
Channel Partners,United States of America,Amarilla,2015,12.00,24180.00,3385.20,20794.80,6045.00,14749.80,12/1/2013,12,December,2013
Small Business,Mexico,Carretera,801,300.00,240300.00,33642.00,206658.00,200250.00,6408.00,7/1/2014,7,July,2014
Enterprise,France,Carretera,1023,125.00,127875.00,17902.50,109972.50,122760.00,-12787.50,9/1/2013,9,September,2013
Small Business,Canada,Carretera,1496,300.00,448800.00,62832.00,385968.00,374000.00,11968.00,10/1/2014,10,October,2014
Small Business,United States of America,Carretera,1010,300.00,303000.00,42420.00,260580.00,252500.00,8080.00,10/1/2014,10,October,2014
Midmarket,Germany,Carretera,1513,15.00,22695.00,3177.30,19517.70,15130.00,4387.70,11/1/2014,11,November,2014
Midmarket,Canada,Carretera,2300,15.00,34500.00,4830.00,29670.00,23000.00,6670.00,12/1/2014,12,December,2014
Enterprise,Mexico,Carretera,2821,125.00,352625.00,49367.50,303257.50,338520.00,-35262.50,12/1/2013,12,December,2013
Government,Canada,Montana,2227.5,350.00,779625.00,109147.50,670477.50,579150.00,91327.50,1/1/2014,1,January,2014
Government,Germany,Montana,1199,350.00,419650.00,58751.00,360899.00,311740.00,49159.00,4/1/2014,4,April,2014
Government,Canada,Montana,200,350.00,70000.00,9800.00,60200.00,52000.00,8200.00,5/1/2014,5,May,2014
Government,Canada,Montana,388,7.00,2716.00,380.24,2335.76,1940.00,395.76,9/1/2014,9,September,2014
Government,Mexico,Montana,1727,7.00,12089.00,1692.46,10396.54,8635.00,1761.54,10/1/2013,10,October,2013
Midmarket,Canada,Montana,2300,15.00,34500.00,4830.00,29670.00,23000.00,6670.00,12/1/2014,12,December,2014
Government,Mexico,Paseo,260,20.00,5200.00,728.00,4472.00,2600.00,1872.00,2/1/2014,2,February,2014
Midmarket,Canada,Paseo,2470,15.00,37050.00,5187.00,31863.00,24700.00,7163.00,9/1/2013,9,September,2013
Midmarket,Canada,Paseo,1743,15.00,26145.00,3660.30,22484.70,17430.00,5054.70,10/1/2013,10,October,2013
Channel Partners,United States of America,Paseo,2914,12.00,34968.00,4895.52,30072.48,8742.00,21330.48,10/1/2014,10,October,2014
Government,France,Paseo,1731,7.00,12117.00,1696.38,10420.62,8655.00,1765.62,10/1/2014,10,October,2014
Government,Canada,Paseo,700,350.00,245000.00,34300.00,210700.00,182000.00,28700.00,11/1/2014,11,November,2014
Channel Partners,Canada,Paseo,2222,12.00,26664.00,3732.96,22931.04,6666.00,16265.04,11/1/2013,11,November,2013
Government,United States of America,Paseo,1177,350.00,411950.00,57673.00,354277.00,306020.00,48257.00,11/1/2014,11,November,2014
Government,France,Paseo,1922,350.00,672700.00,94178.00,578522.00,499720.00,78802.00,11/1/2013,11,November,2013
Enterprise,Mexico,Velo,1575,125.00,196875.00,27562.50,169312.50,189000.00,-19687.50,2/1/2014,2,February,2014
Government,United States of America,Velo,606,20.00,12120.00,1696.80,10423.20,6060.00,4363.20,4/1/2014,4,April,2014
Small Business,United States of America,Velo,2460,300.00,738000.00,103320.00,634680.00,615000.00,19680.00,7/1/2014,7,July,2014
Small Business,Canada,Velo,269,300.00,80700.00,11298.00,69402.00,67250.00,2152.00,10/1/2013,10,October,2013
Small Business,Germany,Velo,2536,300.00,760800.00,106512.00,654288.00,634000.00,20288.00,11/1/2013,11,November,2013
Government,Mexico,VTT,2903,7.00,20321.00,2844.94,17476.06,14515.00,2961.06,3/1/2014,3,March,2014
Small Business,United States of America,VTT,2541,300.00,762300.00,106722.00,655578.00,635250.00,20328.00,8/1/2014,8,August,2014
Small Business,Canada,VTT,269,300.00,80700.00,11298.00,69402.00,67250.00,2152.00,10/1/2013,10,October,2013
Small Business,Canada,VTT,1496,300.00,448800.00,62832.00,385968.00,374000.00,11968.00,10/1/2014,10,October,2014
Small Business,United States of America,VTT,1010,300.00,303000.00,42420.00,260580.00,252500.00,8080.00,10/1/2014,10,October,2014
Government,France,VTT,1281,350.00,448350.00,62769.00,385581.00,333060.00,52521.00,12/1/2013,12,December,2013
Small Business,Canada,Amarilla,888,300.00,266400.00,37296.00,229104.00,222000.00,7104.00,3/1/2014,3,March,2014
Enterprise,United States of America,Amarilla,2844,125.00,355500.00,49770.00,305730.00,341280.00,-35550.00,5/1/2014,5,May,2014
Channel Partners,France,Amarilla,2475,12.00,29700.00,4158.00,25542.00,7425.00,18117.00,8/1/2014,8,August,2014
Midmarket,Canada,Amarilla,1743,15.00,26145.00,3660.30,22484.70,17430.00,5054.70,10/1/2013,10,October,2013
Channel Partners,United States of America,Amarilla,2914,12.00,34968.00,4895.52,30072.48,8742.00,21330.48,10/1/2014,10,October,2014
Government,France,Amarilla,1731,7.00,12117.00,1696.38,10420.62,8655.00,1765.62,10/1/2014,10,October,2014
Government,Mexico,Amarilla,1727,7.00,12089.00,1692.46,10396.54,8635.00,1761.54,10/1/2013,10,October,2013
Midmarket,Mexico,Amarilla,1870,15.00,28050.00,3927.00,24123.00,18700.00,5423.00,11/1/2013,11,November,2013
Enterprise,France,Carretera,1174,125.00,146750.00,22012.50,124737.50,140880.00,-16142.50,8/1/2014,8,August,2014
Enterprise,Germany,Carretera,2767,125.00,345875.00,51881.25,293993.75,332040.00,-38046.25,8/1/2014,8,August,2014
Enterprise,Germany,Carretera,1085,125.00,135625.00,20343.75,115281.25,130200.00,-14918.75,10/1/2014,10,October,2014
Small Business,Mexico,Montana,546,300.00,163800.00,24570.00,139230.00,136500.00,2730.00,10/1/2014,10,October,2014
Government,Germany,Paseo,1158,20.00,23160.00,3474.00,19686.00,11580.00,8106.00,3/1/2014,3,March,2014
Midmarket,Canada,Paseo,1614,15.00,24210.00,3631.50,20578.50,16140.00,4438.50,4/1/2014,4,April,2014
Government,Mexico,Paseo,2535,7.00,17745.00,2661.75,15083.25,12675.00,2408.25,4/1/2014,4,April,2014
Government,Mexico,Paseo,2851,350.00,997850.00,149677.50,848172.50,741260.00,106912.50,5/1/2014,5,May,2014
Midmarket,Canada,Paseo,2559,15.00,38385.00,5757.75,32627.25,25590.00,7037.25,8/1/2014,8,August,2014
Government,United States of America,Paseo,267,20.00,5340.00,801.00,4539.00,2670.00,1869.00,10/1/2013,10,October,2013
Enterprise,Germany,Paseo,1085,125.00,135625.00,20343.75,115281.25,130200.00,-14918.75,10/1/2014,10,October,2014
Midmarket,Germany,Paseo,1175,15.00,17625.00,2643.75,14981.25,11750.00,3231.25,10/1/2014,10,October,2014
Government,United States of America,Paseo,2007,350.00,702450.00,105367.50,597082.50,521820.00,75262.50,11/1/2013,11,November,2013
Government,Mexico,Paseo,2151,350.00,752850.00,112927.50,639922.50,559260.00,80662.50,11/1/2013,11,November,2013
Channel Partners,United States of America,Paseo,914,12.00,10968.00,1645.20,9322.80,2742.00,6580.80,12/1/2014,12,December,2014
Government,France,Paseo,293,20.00,5860.00,879.00,4981.00,2930.00,2051.00,12/1/2014,12,December,2014
Channel Partners,Mexico,Velo,500,12.00,6000.00,900.00,5100.00,1500.00,3600.00,3/1/2014,3,March,2014
Midmarket,France,Velo,2826,15.00,42390.00,6358.50,36031.50,28260.00,7771.50,5/1/2014,5,May,2014
Enterprise,France,Velo,663,125.00,82875.00,12431.25,70443.75,79560.00,-9116.25,9/1/2014,9,September,2014
Small Business,United States of America,Velo,2574,300.00,772200.00,115830.00,656370.00,643500.00,12870.00,11/1/2013,11,November,2013
Enterprise,United States of America,Velo,2438,125.00,304750.00,45712.50,259037.50,292560.00,-33522.50,12/1/2013,12,December,2013
Channel Partners,United States of America,Velo,914,12.00,10968.00,1645.20,9322.80,2742.00,6580.80,12/1/2014,12,December,2014
Government,Canada,VTT,865.5,20.00,17310.00,2596.50,14713.50,8655.00,6058.50,7/1/2014,7,July,2014
Midmarket,Germany,VTT,492,15.00,7380.00,1107.00,6273.00,4920.00,1353.00,7/1/2014,7,July,2014
Government,United States of America,VTT,267,20.00,5340.00,801.00,4539.00,2670.00,1869.00,10/1/2013,10,October,2013
Midmarket,Germany,VTT,1175,15.00,17625.00,2643.75,14981.25,11750.00,3231.25,10/1/2014,10,October,2014
Enterprise,Canada,VTT,2954,125.00,369250.00,55387.50,313862.50,354480.00,-40617.50,11/1/2013,11,November,2013
Enterprise,Germany,VTT,552,125.00,69000.00,10350.00,58650.00,66240.00,-7590.00,11/1/2014,11,November,2014
Government,France,VTT,293,20.00,5860.00,879.00,4981.00,2930.00,2051.00,12/1/2014,12,December,2014
Small Business,France,Amarilla,2475,300.00,742500.00,111375.00,631125.00,618750.00,12375.00,3/1/2014,3,March,2014
Small Business,Mexico,Amarilla,546,300.00,163800.00,24570.00,139230.00,136500.00,2730.00,10/1/2014,10,October,2014
Government,Mexico,Montana,1368,7.00,9576.00,1436.40,8139.60,6840.00,1299.60,2/1/2014,2,February,2014
Government,Canada,Paseo,723,7.00,5061.00,759.15,4301.85,3615.00,686.85,4/1/2014,4,April,2014
Channel Partners,United States of America,VTT,1806,12.00,21672.00,3250.80,18421.20,5418.00,13003.20,5/1/2014,5,May,2014
1 Segment Country Product Units Sold Sale Price Gross Sales Discounts Sales COGS Profit Date Month Number Month Name Year
2 Government Canada Carretera 1618.5 20.00 32370.00 0.00 32370.00 16185.00 16185.00 1/1/2014 1 January 2014
3 Government Germany Carretera 1321 20.00 26420.00 0.00 26420.00 13210.00 13210.00 1/1/2014 1 January 2014
4 Midmarket France Carretera 2178 15.00 32670.00 0.00 32670.00 21780.00 10890.00 6/1/2014 6 June 2014
5 Midmarket Germany Carretera 888 15.00 13320.00 0.00 13320.00 8880.00 4440.00 6/1/2014 6 June 2014
6 Midmarket Mexico Carretera 2470 15.00 37050.00 0.00 37050.00 24700.00 12350.00 6/1/2014 6 June 2014
7 Government Germany Carretera 1513 350.00 529550.00 0.00 529550.00 393380.00 136170.00 12/1/2014 12 December 2014
8 Midmarket Germany Montana 921 15.00 13815.00 0.00 13815.00 9210.00 4605.00 3/1/2014 3 March 2014
9 Channel Partners Canada Montana 2518 12.00 30216.00 0.00 30216.00 7554.00 22662.00 6/1/2014 6 June 2014
10 Government France Montana 1899 20.00 37980.00 0.00 37980.00 18990.00 18990.00 6/1/2014 6 June 2014
11 Channel Partners Germany Montana 1545 12.00 18540.00 0.00 18540.00 4635.00 13905.00 6/1/2014 6 June 2014
12 Midmarket Mexico Montana 2470 15.00 37050.00 0.00 37050.00 24700.00 12350.00 6/1/2014 6 June 2014
13 Enterprise Canada Montana 2665.5 125.00 333187.50 0.00 333187.50 319860.00 13327.50 7/1/2014 7 July 2014
14 Small Business Mexico Montana 958 300.00 287400.00 0.00 287400.00 239500.00 47900.00 8/1/2014 8 August 2014
15 Government Germany Montana 2146 7.00 15022.00 0.00 15022.00 10730.00 4292.00 9/1/2014 9 September 2014
16 Enterprise Canada Montana 345 125.00 43125.00 0.00 43125.00 41400.00 1725.00 10/1/2013 10 October 2013
17 Midmarket United States of America Montana 615 15.00 9225.00 0.00 9225.00 6150.00 3075.00 12/1/2014 12 December 2014
18 Government Canada Paseo 292 20.00 5840.00 0.00 5840.00 2920.00 2920.00 2/1/2014 2 February 2014
19 Midmarket Mexico Paseo 974 15.00 14610.00 0.00 14610.00 9740.00 4870.00 2/1/2014 2 February 2014
20 Channel Partners Canada Paseo 2518 12.00 30216.00 0.00 30216.00 7554.00 22662.00 6/1/2014 6 June 2014
21 Government Germany Paseo 1006 350.00 352100.00 0.00 352100.00 261560.00 90540.00 6/1/2014 6 June 2014
22 Channel Partners Germany Paseo 367 12.00 4404.00 0.00 4404.00 1101.00 3303.00 7/1/2014 7 July 2014
23 Government Mexico Paseo 883 7.00 6181.00 0.00 6181.00 4415.00 1766.00 8/1/2014 8 August 2014
24 Midmarket France Paseo 549 15.00 8235.00 0.00 8235.00 5490.00 2745.00 9/1/2013 9 September 2013
25 Small Business Mexico Paseo 788 300.00 236400.00 0.00 236400.00 197000.00 39400.00 9/1/2013 9 September 2013
26 Midmarket Mexico Paseo 2472 15.00 37080.00 0.00 37080.00 24720.00 12360.00 9/1/2014 9 September 2014
27 Government United States of America Paseo 1143 7.00 8001.00 0.00 8001.00 5715.00 2286.00 10/1/2014 10 October 2014
28 Government Canada Paseo 1725 350.00 603750.00 0.00 603750.00 448500.00 155250.00 11/1/2013 11 November 2013
29 Channel Partners United States of America Paseo 912 12.00 10944.00 0.00 10944.00 2736.00 8208.00 11/1/2013 11 November 2013
30 Midmarket Canada Paseo 2152 15.00 32280.00 0.00 32280.00 21520.00 10760.00 12/1/2013 12 December 2013
31 Government Canada Paseo 1817 20.00 36340.00 0.00 36340.00 18170.00 18170.00 12/1/2014 12 December 2014
32 Government Germany Paseo 1513 350.00 529550.00 0.00 529550.00 393380.00 136170.00 12/1/2014 12 December 2014
33 Government Mexico Velo 1493 7.00 10451.00 0.00 10451.00 7465.00 2986.00 1/1/2014 1 January 2014
34 Enterprise France Velo 1804 125.00 225500.00 0.00 225500.00 216480.00 9020.00 2/1/2014 2 February 2014
35 Channel Partners Germany Velo 2161 12.00 25932.00 0.00 25932.00 6483.00 19449.00 3/1/2014 3 March 2014
36 Government Germany Velo 1006 350.00 352100.00 0.00 352100.00 261560.00 90540.00 6/1/2014 6 June 2014
37 Channel Partners Germany Velo 1545 12.00 18540.00 0.00 18540.00 4635.00 13905.00 6/1/2014 6 June 2014
38 Enterprise United States of America Velo 2821 125.00 352625.00 0.00 352625.00 338520.00 14105.00 8/1/2014 8 August 2014
39 Enterprise Canada Velo 345 125.00 43125.00 0.00 43125.00 41400.00 1725.00 10/1/2013 10 October 2013
40 Small Business Canada VTT 2001 300.00 600300.00 0.00 600300.00 500250.00 100050.00 2/1/2014 2 February 2014
41 Channel Partners Germany VTT 2838 12.00 34056.00 0.00 34056.00 8514.00 25542.00 4/1/2014 4 April 2014
42 Midmarket France VTT 2178 15.00 32670.00 0.00 32670.00 21780.00 10890.00 6/1/2014 6 June 2014
43 Midmarket Germany VTT 888 15.00 13320.00 0.00 13320.00 8880.00 4440.00 6/1/2014 6 June 2014
44 Government France VTT 1527 350.00 534450.00 0.00 534450.00 397020.00 137430.00 9/1/2013 9 September 2013
45 Small Business France VTT 2151 300.00 645300.00 0.00 645300.00 537750.00 107550.00 9/1/2014 9 September 2014
46 Government Canada VTT 1817 20.00 36340.00 0.00 36340.00 18170.00 18170.00 12/1/2014 12 December 2014
47 Government France Amarilla 2750 350.00 962500.00 0.00 962500.00 715000.00 247500.00 2/1/2014 2 February 2014
48 Channel Partners United States of America Amarilla 1953 12.00 23436.00 0.00 23436.00 5859.00 17577.00 4/1/2014 4 April 2014
49 Enterprise Germany Amarilla 4219.5 125.00 527437.50 0.00 527437.50 506340.00 21097.50 4/1/2014 4 April 2014
50 Government France Amarilla 1899 20.00 37980.00 0.00 37980.00 18990.00 18990.00 6/1/2014 6 June 2014
51 Government Germany Amarilla 1686 7.00 11802.00 0.00 11802.00 8430.00 3372.00 7/1/2014 7 July 2014
52 Channel Partners United States of America Amarilla 2141 12.00 25692.00 0.00 25692.00 6423.00 19269.00 8/1/2014 8 August 2014
53 Government United States of America Amarilla 1143 7.00 8001.00 0.00 8001.00 5715.00 2286.00 10/1/2014 10 October 2014
54 Midmarket United States of America Amarilla 615 15.00 9225.00 0.00 9225.00 6150.00 3075.00 12/1/2014 12 December 2014
55 Government France Paseo 3945 7.00 27615.00 276.15 27338.85 19725.00 7613.85 1/1/2014 1 January 2014
56 Midmarket France Paseo 2296 15.00 34440.00 344.40 34095.60 22960.00 11135.60 2/1/2014 2 February 2014
57 Government France Paseo 1030 7.00 7210.00 72.10 7137.90 5150.00 1987.90 5/1/2014 5 May 2014
58 Government France Velo 639 7.00 4473.00 44.73 4428.27 3195.00 1233.27 11/1/2014 11 November 2014
59 Government Canada VTT 1326 7.00 9282.00 92.82 9189.18 6630.00 2559.18 3/1/2014 3 March 2014
60 Channel Partners United States of America Carretera 1858 12.00 22296.00 222.96 22073.04 5574.00 16499.04 2/1/2014 2 February 2014
61 Government Mexico Carretera 1210 350.00 423500.00 4235.00 419265.00 314600.00 104665.00 3/1/2014 3 March 2014
62 Government United States of America Carretera 2529 7.00 17703.00 177.03 17525.97 12645.00 4880.97 7/1/2014 7 July 2014
63 Channel Partners Canada Carretera 1445 12.00 17340.00 173.40 17166.60 4335.00 12831.60 9/1/2014 9 September 2014
64 Enterprise United States of America Carretera 330 125.00 41250.00 412.50 40837.50 39600.00 1237.50 9/1/2013 9 September 2013
65 Channel Partners France Carretera 2671 12.00 32052.00 320.52 31731.48 8013.00 23718.48 9/1/2014 9 September 2014
66 Channel Partners Germany Carretera 766 12.00 9192.00 91.92 9100.08 2298.00 6802.08 10/1/2013 10 October 2013
67 Small Business Mexico Carretera 494 300.00 148200.00 1482.00 146718.00 123500.00 23218.00 10/1/2013 10 October 2013
68 Government Mexico Carretera 1397 350.00 488950.00 4889.50 484060.50 363220.00 120840.50 10/1/2014 10 October 2014
69 Government France Carretera 2155 350.00 754250.00 7542.50 746707.50 560300.00 186407.50 12/1/2014 12 December 2014
70 Midmarket Mexico Montana 2214 15.00 33210.00 332.10 32877.90 22140.00 10737.90 3/1/2014 3 March 2014
71 Small Business United States of America Montana 2301 300.00 690300.00 6903.00 683397.00 575250.00 108147.00 4/1/2014 4 April 2014
72 Government France Montana 1375.5 20.00 27510.00 275.10 27234.90 13755.00 13479.90 7/1/2014 7 July 2014
73 Government Canada Montana 1830 7.00 12810.00 128.10 12681.90 9150.00 3531.90 8/1/2014 8 August 2014
74 Small Business United States of America Montana 2498 300.00 749400.00 7494.00 741906.00 624500.00 117406.00 9/1/2013 9 September 2013
75 Enterprise United States of America Montana 663 125.00 82875.00 828.75 82046.25 79560.00 2486.25 10/1/2013 10 October 2013
76 Midmarket United States of America Paseo 1514 15.00 22710.00 227.10 22482.90 15140.00 7342.90 2/1/2014 2 February 2014
77 Government United States of America Paseo 4492.5 7.00 31447.50 314.48 31133.03 22462.50 8670.53 4/1/2014 4 April 2014
78 Enterprise United States of America Paseo 727 125.00 90875.00 908.75 89966.25 87240.00 2726.25 6/1/2014 6 June 2014
79 Enterprise France Paseo 787 125.00 98375.00 983.75 97391.25 94440.00 2951.25 6/1/2014 6 June 2014
80 Enterprise Mexico Paseo 1823 125.00 227875.00 2278.75 225596.25 218760.00 6836.25 7/1/2014 7 July 2014
81 Midmarket Germany Paseo 747 15.00 11205.00 112.05 11092.95 7470.00 3622.95 9/1/2014 9 September 2014
82 Channel Partners Germany Paseo 766 12.00 9192.00 91.92 9100.08 2298.00 6802.08 10/1/2013 10 October 2013
83 Small Business United States of America Paseo 2905 300.00 871500.00 8715.00 862785.00 726250.00 136535.00 11/1/2014 11 November 2014
84 Government France Paseo 2155 350.00 754250.00 7542.50 746707.50 560300.00 186407.50 12/1/2014 12 December 2014
85 Government France Velo 3864 20.00 77280.00 772.80 76507.20 38640.00 37867.20 4/1/2014 4 April 2014
86 Government Mexico Velo 362 7.00 2534.00 25.34 2508.66 1810.00 698.66 5/1/2014 5 May 2014
87 Enterprise Canada Velo 923 125.00 115375.00 1153.75 114221.25 110760.00 3461.25 8/1/2014 8 August 2014
88 Enterprise United States of America Velo 663 125.00 82875.00 828.75 82046.25 79560.00 2486.25 10/1/2013 10 October 2013
89 Government Canada Velo 2092 7.00 14644.00 146.44 14497.56 10460.00 4037.56 11/1/2013 11 November 2013
90 Government Germany VTT 263 7.00 1841.00 18.41 1822.59 1315.00 507.59 3/1/2014 3 March 2014
91 Government Canada VTT 943.5 350.00 330225.00 3302.25 326922.75 245310.00 81612.75 4/1/2014 4 April 2014
92 Enterprise United States of America VTT 727 125.00 90875.00 908.75 89966.25 87240.00 2726.25 6/1/2014 6 June 2014
93 Enterprise France VTT 787 125.00 98375.00 983.75 97391.25 94440.00 2951.25 6/1/2014 6 June 2014
94 Small Business Germany VTT 986 300.00 295800.00 2958.00 292842.00 246500.00 46342.00 9/1/2014 9 September 2014
95 Small Business Mexico VTT 494 300.00 148200.00 1482.00 146718.00 123500.00 23218.00 10/1/2013 10 October 2013
96 Government Mexico VTT 1397 350.00 488950.00 4889.50 484060.50 363220.00 120840.50 10/1/2014 10 October 2014
97 Enterprise France VTT 1744 125.00 218000.00 2180.00 215820.00 209280.00 6540.00 11/1/2014 11 November 2014
98 Channel Partners United States of America Amarilla 1989 12.00 23868.00 238.68 23629.32 5967.00 17662.32 9/1/2013 9 September 2013
99 Midmarket France Amarilla 321 15.00 4815.00 48.15 4766.85 3210.00 1556.85 11/1/2013 11 November 2013
100 Enterprise Canada Carretera 742.5 125.00 92812.50 1856.25 90956.25 89100.00 1856.25 4/1/2014 4 April 2014
101 Channel Partners Canada Carretera 1295 12.00 15540.00 310.80 15229.20 3885.00 11344.20 10/1/2014 10 October 2014
102 Small Business Germany Carretera 214 300.00 64200.00 1284.00 62916.00 53500.00 9416.00 10/1/2013 10 October 2013
103 Government France Carretera 2145 7.00 15015.00 300.30 14714.70 10725.00 3989.70 11/1/2013 11 November 2013
104 Government Canada Carretera 2852 350.00 998200.00 19964.00 978236.00 741520.00 236716.00 12/1/2014 12 December 2014
105 Channel Partners United States of America Montana 1142 12.00 13704.00 274.08 13429.92 3426.00 10003.92 6/1/2014 6 June 2014
106 Government United States of America Montana 1566 20.00 31320.00 626.40 30693.60 15660.00 15033.60 10/1/2014 10 October 2014
107 Channel Partners Mexico Montana 690 12.00 8280.00 165.60 8114.40 2070.00 6044.40 11/1/2014 11 November 2014
108 Enterprise Mexico Montana 1660 125.00 207500.00 4150.00 203350.00 199200.00 4150.00 11/1/2013 11 November 2013
109 Midmarket Canada Paseo 2363 15.00 35445.00 708.90 34736.10 23630.00 11106.10 2/1/2014 2 February 2014
110 Small Business France Paseo 918 300.00 275400.00 5508.00 269892.00 229500.00 40392.00 5/1/2014 5 May 2014
111 Small Business Germany Paseo 1728 300.00 518400.00 10368.00 508032.00 432000.00 76032.00 5/1/2014 5 May 2014
112 Channel Partners United States of America Paseo 1142 12.00 13704.00 274.08 13429.92 3426.00 10003.92 6/1/2014 6 June 2014
113 Enterprise Mexico Paseo 662 125.00 82750.00 1655.00 81095.00 79440.00 1655.00 6/1/2014 6 June 2014
114 Channel Partners Canada Paseo 1295 12.00 15540.00 310.80 15229.20 3885.00 11344.20 10/1/2014 10 October 2014
115 Enterprise Germany Paseo 809 125.00 101125.00 2022.50 99102.50 97080.00 2022.50 10/1/2013 10 October 2013
116 Enterprise Mexico Paseo 2145 125.00 268125.00 5362.50 262762.50 257400.00 5362.50 10/1/2013 10 October 2013
117 Channel Partners France Paseo 1785 12.00 21420.00 428.40 20991.60 5355.00 15636.60 11/1/2013 11 November 2013
118 Small Business Canada Paseo 1916 300.00 574800.00 11496.00 563304.00 479000.00 84304.00 12/1/2014 12 December 2014
119 Government Canada Paseo 2852 350.00 998200.00 19964.00 978236.00 741520.00 236716.00 12/1/2014 12 December 2014
120 Enterprise Canada Paseo 2729 125.00 341125.00 6822.50 334302.50 327480.00 6822.50 12/1/2014 12 December 2014
121 Midmarket United States of America Paseo 1925 15.00 28875.00 577.50 28297.50 19250.00 9047.50 12/1/2013 12 December 2013
122 Government United States of America Paseo 2013 7.00 14091.00 281.82 13809.18 10065.00 3744.18 12/1/2013 12 December 2013
123 Channel Partners France Paseo 1055 12.00 12660.00 253.20 12406.80 3165.00 9241.80 12/1/2014 12 December 2014
124 Channel Partners Mexico Paseo 1084 12.00 13008.00 260.16 12747.84 3252.00 9495.84 12/1/2014 12 December 2014
125 Government United States of America Velo 1566 20.00 31320.00 626.40 30693.60 15660.00 15033.60 10/1/2014 10 October 2014
126 Government Germany Velo 2966 350.00 1038100.00 20762.00 1017338.00 771160.00 246178.00 10/1/2013 10 October 2013
127 Government Germany Velo 2877 350.00 1006950.00 20139.00 986811.00 748020.00 238791.00 10/1/2014 10 October 2014
128 Enterprise Germany Velo 809 125.00 101125.00 2022.50 99102.50 97080.00 2022.50 10/1/2013 10 October 2013
129 Enterprise Mexico Velo 2145 125.00 268125.00 5362.50 262762.50 257400.00 5362.50 10/1/2013 10 October 2013
130 Channel Partners France Velo 1055 12.00 12660.00 253.20 12406.80 3165.00 9241.80 12/1/2014 12 December 2014
131 Government Mexico Velo 544 20.00 10880.00 217.60 10662.40 5440.00 5222.40 12/1/2013 12 December 2013
132 Channel Partners Mexico Velo 1084 12.00 13008.00 260.16 12747.84 3252.00 9495.84 12/1/2014 12 December 2014
133 Enterprise Mexico VTT 662 125.00 82750.00 1655.00 81095.00 79440.00 1655.00 6/1/2014 6 June 2014
134 Small Business Germany VTT 214 300.00 64200.00 1284.00 62916.00 53500.00 9416.00 10/1/2013 10 October 2013
135 Government Germany VTT 2877 350.00 1006950.00 20139.00 986811.00 748020.00 238791.00 10/1/2014 10 October 2014
136 Enterprise Canada VTT 2729 125.00 341125.00 6822.50 334302.50 327480.00 6822.50 12/1/2014 12 December 2014
137 Government United States of America VTT 266 350.00 93100.00 1862.00 91238.00 69160.00 22078.00 12/1/2013 12 December 2013
138 Government Mexico VTT 1940 350.00 679000.00 13580.00 665420.00 504400.00 161020.00 12/1/2013 12 December 2013
139 Small Business Germany Amarilla 259 300.00 77700.00 1554.00 76146.00 64750.00 11396.00 3/1/2014 3 March 2014
140 Small Business Mexico Amarilla 1101 300.00 330300.00 6606.00 323694.00 275250.00 48444.00 3/1/2014 3 March 2014
141 Enterprise Germany Amarilla 2276 125.00 284500.00 5690.00 278810.00 273120.00 5690.00 5/1/2014 5 May 2014
142 Government Germany Amarilla 2966 350.00 1038100.00 20762.00 1017338.00 771160.00 246178.00 10/1/2013 10 October 2013
143 Government United States of America Amarilla 1236 20.00 24720.00 494.40 24225.60 12360.00 11865.60 11/1/2014 11 November 2014
144 Government France Amarilla 941 20.00 18820.00 376.40 18443.60 9410.00 9033.60 11/1/2014 11 November 2014
145 Small Business Canada Amarilla 1916 300.00 574800.00 11496.00 563304.00 479000.00 84304.00 12/1/2014 12 December 2014
146 Enterprise France Carretera 4243.5 125.00 530437.50 15913.13 514524.38 509220.00 5304.38 4/1/2014 4 April 2014
147 Government Germany Carretera 2580 20.00 51600.00 1548.00 50052.00 25800.00 24252.00 4/1/2014 4 April 2014
148 Small Business Germany Carretera 689 300.00 206700.00 6201.00 200499.00 172250.00 28249.00 6/1/2014 6 June 2014
149 Channel Partners United States of America Carretera 1947 12.00 23364.00 700.92 22663.08 5841.00 16822.08 9/1/2014 9 September 2014
150 Channel Partners Canada Carretera 908 12.00 10896.00 326.88 10569.12 2724.00 7845.12 12/1/2013 12 December 2013
151 Government Germany Montana 1958 7.00 13706.00 411.18 13294.82 9790.00 3504.82 2/1/2014 2 February 2014
152 Channel Partners France Montana 1901 12.00 22812.00 684.36 22127.64 5703.00 16424.64 6/1/2014 6 June 2014
153 Government France Montana 544 7.00 3808.00 114.24 3693.76 2720.00 973.76 9/1/2014 9 September 2014
154 Government Germany Montana 1797 350.00 628950.00 18868.50 610081.50 467220.00 142861.50 9/1/2013 9 September 2013
155 Enterprise France Montana 1287 125.00 160875.00 4826.25 156048.75 154440.00 1608.75 12/1/2014 12 December 2014
156 Enterprise Germany Montana 1706 125.00 213250.00 6397.50 206852.50 204720.00 2132.50 12/1/2014 12 December 2014
157 Small Business France Paseo 2434.5 300.00 730350.00 21910.50 708439.50 608625.00 99814.50 1/1/2014 1 January 2014
158 Enterprise Canada Paseo 1774 125.00 221750.00 6652.50 215097.50 212880.00 2217.50 3/1/2014 3 March 2014
159 Channel Partners France Paseo 1901 12.00 22812.00 684.36 22127.64 5703.00 16424.64 6/1/2014 6 June 2014
160 Small Business Germany Paseo 689 300.00 206700.00 6201.00 200499.00 172250.00 28249.00 6/1/2014 6 June 2014
161 Enterprise Germany Paseo 1570 125.00 196250.00 5887.50 190362.50 188400.00 1962.50 6/1/2014 6 June 2014
162 Channel Partners United States of America Paseo 1369.5 12.00 16434.00 493.02 15940.98 4108.50 11832.48 7/1/2014 7 July 2014
163 Enterprise Canada Paseo 2009 125.00 251125.00 7533.75 243591.25 241080.00 2511.25 10/1/2014 10 October 2014
164 Midmarket Germany Paseo 1945 15.00 29175.00 875.25 28299.75 19450.00 8849.75 10/1/2013 10 October 2013
165 Enterprise France Paseo 1287 125.00 160875.00 4826.25 156048.75 154440.00 1608.75 12/1/2014 12 December 2014
166 Enterprise Germany Paseo 1706 125.00 213250.00 6397.50 206852.50 204720.00 2132.50 12/1/2014 12 December 2014
167 Enterprise Canada Velo 2009 125.00 251125.00 7533.75 243591.25 241080.00 2511.25 10/1/2014 10 October 2014
168 Small Business United States of America VTT 2844 300.00 853200.00 25596.00 827604.00 711000.00 116604.00 2/1/2014 2 February 2014
169 Channel Partners Mexico VTT 1916 12.00 22992.00 689.76 22302.24 5748.00 16554.24 4/1/2014 4 April 2014
170 Enterprise Germany VTT 1570 125.00 196250.00 5887.50 190362.50 188400.00 1962.50 6/1/2014 6 June 2014
171 Small Business Canada VTT 1874 300.00 562200.00 16866.00 545334.00 468500.00 76834.00 8/1/2014 8 August 2014
172 Government Mexico VTT 1642 350.00 574700.00 17241.00 557459.00 426920.00 130539.00 8/1/2014 8 August 2014
173 Midmarket Germany VTT 1945 15.00 29175.00 875.25 28299.75 19450.00 8849.75 10/1/2013 10 October 2013
174 Government Canada Carretera 831 20.00 16620.00 498.60 16121.40 8310.00 7811.40 5/1/2014 5 May 2014
175 Government Mexico Paseo 1760 7.00 12320.00 369.60 11950.40 8800.00 3150.40 9/1/2013 9 September 2013
176 Government Canada Velo 3850.5 20.00 77010.00 2310.30 74699.70 38505.00 36194.70 4/1/2014 4 April 2014
177 Channel Partners Germany VTT 2479 12.00 29748.00 892.44 28855.56 7437.00 21418.56 1/1/2014 1 January 2014
178 Midmarket Mexico Montana 2031 15.00 30465.00 1218.60 29246.40 20310.00 8936.40 10/1/2014 10 October 2014
179 Midmarket Mexico Paseo 2031 15.00 30465.00 1218.60 29246.40 20310.00 8936.40 10/1/2014 10 October 2014
180 Midmarket France Paseo 2261 15.00 33915.00 1356.60 32558.40 22610.00 9948.40 12/1/2013 12 December 2013
181 Government United States of America Velo 736 20.00 14720.00 588.80 14131.20 7360.00 6771.20 9/1/2013 9 September 2013
182 Government Canada Carretera 2851 7.00 19957.00 798.28 19158.72 14255.00 4903.72 10/1/2013 10 October 2013
183 Small Business Germany Carretera 2021 300.00 606300.00 24252.00 582048.00 505250.00 76798.00 10/1/2014 10 October 2014
184 Government United States of America Carretera 274 350.00 95900.00 3836.00 92064.00 71240.00 20824.00 12/1/2014 12 December 2014
185 Midmarket Canada Montana 1967 15.00 29505.00 1180.20 28324.80 19670.00 8654.80 3/1/2014 3 March 2014
186 Small Business Germany Montana 1859 300.00 557700.00 22308.00 535392.00 464750.00 70642.00 8/1/2014 8 August 2014
187 Government Canada Montana 2851 7.00 19957.00 798.28 19158.72 14255.00 4903.72 10/1/2013 10 October 2013
188 Small Business Germany Montana 2021 300.00 606300.00 24252.00 582048.00 505250.00 76798.00 10/1/2014 10 October 2014
189 Enterprise Mexico Montana 1138 125.00 142250.00 5690.00 136560.00 136560.00 0.00 12/1/2014 12 December 2014
190 Government Canada Paseo 4251 7.00 29757.00 1190.28 28566.72 21255.00 7311.72 1/1/2014 1 January 2014
191 Enterprise Germany Paseo 795 125.00 99375.00 3975.00 95400.00 95400.00 0.00 3/1/2014 3 March 2014
192 Small Business Germany Paseo 1414.5 300.00 424350.00 16974.00 407376.00 353625.00 53751.00 4/1/2014 4 April 2014
193 Small Business United States of America Paseo 2918 300.00 875400.00 35016.00 840384.00 729500.00 110884.00 5/1/2014 5 May 2014
194 Government United States of America Paseo 3450 350.00 1207500.00 48300.00 1159200.00 897000.00 262200.00 7/1/2014 7 July 2014
195 Enterprise France Paseo 2988 125.00 373500.00 14940.00 358560.00 358560.00 0.00 7/1/2014 7 July 2014
196 Midmarket Canada Paseo 218 15.00 3270.00 130.80 3139.20 2180.00 959.20 9/1/2014 9 September 2014
197 Government Canada Paseo 2074 20.00 41480.00 1659.20 39820.80 20740.00 19080.80 9/1/2014 9 September 2014
198 Government United States of America Paseo 1056 20.00 21120.00 844.80 20275.20 10560.00 9715.20 9/1/2014 9 September 2014
199 Midmarket United States of America Paseo 671 15.00 10065.00 402.60 9662.40 6710.00 2952.40 10/1/2013 10 October 2013
200 Midmarket Mexico Paseo 1514 15.00 22710.00 908.40 21801.60 15140.00 6661.60 10/1/2013 10 October 2013
201 Government United States of America Paseo 274 350.00 95900.00 3836.00 92064.00 71240.00 20824.00 12/1/2014 12 December 2014
202 Enterprise Mexico Paseo 1138 125.00 142250.00 5690.00 136560.00 136560.00 0.00 12/1/2014 12 December 2014
203 Channel Partners United States of America Velo 1465 12.00 17580.00 703.20 16876.80 4395.00 12481.80 3/1/2014 3 March 2014
204 Government Canada Velo 2646 20.00 52920.00 2116.80 50803.20 26460.00 24343.20 9/1/2013 9 September 2013
205 Government France Velo 2177 350.00 761950.00 30478.00 731472.00 566020.00 165452.00 10/1/2014 10 October 2014
206 Channel Partners France VTT 866 12.00 10392.00 415.68 9976.32 2598.00 7378.32 5/1/2014 5 May 2014
207 Government United States of America VTT 349 350.00 122150.00 4886.00 117264.00 90740.00 26524.00 9/1/2013 9 September 2013
208 Government France VTT 2177 350.00 761950.00 30478.00 731472.00 566020.00 165452.00 10/1/2014 10 October 2014
209 Midmarket Mexico VTT 1514 15.00 22710.00 908.40 21801.60 15140.00 6661.60 10/1/2013 10 October 2013
210 Government Mexico Amarilla 1865 350.00 652750.00 26110.00 626640.00 484900.00 141740.00 2/1/2014 2 February 2014
211 Enterprise Mexico Amarilla 1074 125.00 134250.00 5370.00 128880.00 128880.00 0.00 4/1/2014 4 April 2014
212 Government Germany Amarilla 1907 350.00 667450.00 26698.00 640752.00 495820.00 144932.00 9/1/2014 9 September 2014
213 Midmarket United States of America Amarilla 671 15.00 10065.00 402.60 9662.40 6710.00 2952.40 10/1/2013 10 October 2013
214 Government Canada Amarilla 1778 350.00 622300.00 24892.00 597408.00 462280.00 135128.00 12/1/2013 12 December 2013
215 Government Germany Montana 1159 7.00 8113.00 405.65 7707.35 5795.00 1912.35 10/1/2013 10 October 2013
216 Government Germany Paseo 1372 7.00 9604.00 480.20 9123.80 6860.00 2263.80 1/1/2014 1 January 2014
217 Government Canada Paseo 2349 7.00 16443.00 822.15 15620.85 11745.00 3875.85 9/1/2013 9 September 2013
218 Government Mexico Paseo 2689 7.00 18823.00 941.15 17881.85 13445.00 4436.85 10/1/2014 10 October 2014
219 Channel Partners Canada Paseo 2431 12.00 29172.00 1458.60 27713.40 7293.00 20420.40 12/1/2014 12 December 2014
220 Channel Partners Canada Velo 2431 12.00 29172.00 1458.60 27713.40 7293.00 20420.40 12/1/2014 12 December 2014
221 Government Mexico VTT 2689 7.00 18823.00 941.15 17881.85 13445.00 4436.85 10/1/2014 10 October 2014
222 Government Mexico Amarilla 1683 7.00 11781.00 589.05 11191.95 8415.00 2776.95 7/1/2014 7 July 2014
223 Channel Partners Mexico Amarilla 1123 12.00 13476.00 673.80 12802.20 3369.00 9433.20 8/1/2014 8 August 2014
224 Government Germany Amarilla 1159 7.00 8113.00 405.65 7707.35 5795.00 1912.35 10/1/2013 10 October 2013
225 Channel Partners France Carretera 1865 12.00 22380.00 1119.00 21261.00 5595.00 15666.00 2/1/2014 2 February 2014
226 Channel Partners Germany Carretera 1116 12.00 13392.00 669.60 12722.40 3348.00 9374.40 2/1/2014 2 February 2014
227 Government France Carretera 1563 20.00 31260.00 1563.00 29697.00 15630.00 14067.00 5/1/2014 5 May 2014
228 Small Business United States of America Carretera 991 300.00 297300.00 14865.00 282435.00 247750.00 34685.00 6/1/2014 6 June 2014
229 Government Germany Carretera 1016 7.00 7112.00 355.60 6756.40 5080.00 1676.40 11/1/2013 11 November 2013
230 Midmarket Mexico Carretera 2791 15.00 41865.00 2093.25 39771.75 27910.00 11861.75 11/1/2014 11 November 2014
231 Government United States of America Carretera 570 7.00 3990.00 199.50 3790.50 2850.00 940.50 12/1/2014 12 December 2014
232 Government France Carretera 2487 7.00 17409.00 870.45 16538.55 12435.00 4103.55 12/1/2014 12 December 2014
233 Government France Montana 1384.5 350.00 484575.00 24228.75 460346.25 359970.00 100376.25 1/1/2014 1 January 2014
234 Enterprise United States of America Montana 3627 125.00 453375.00 22668.75 430706.25 435240.00 -4533.75 7/1/2014 7 July 2014
235 Government Mexico Montana 720 350.00 252000.00 12600.00 239400.00 187200.00 52200.00 9/1/2013 9 September 2013
236 Channel Partners Germany Montana 2342 12.00 28104.00 1405.20 26698.80 7026.00 19672.80 11/1/2014 11 November 2014
237 Small Business Mexico Montana 1100 300.00 330000.00 16500.00 313500.00 275000.00 38500.00 12/1/2013 12 December 2013
238 Government France Paseo 1303 20.00 26060.00 1303.00 24757.00 13030.00 11727.00 2/1/2014 2 February 2014
239 Enterprise United States of America Paseo 2992 125.00 374000.00 18700.00 355300.00 359040.00 -3740.00 3/1/2014 3 March 2014
240 Enterprise France Paseo 2385 125.00 298125.00 14906.25 283218.75 286200.00 -2981.25 3/1/2014 3 March 2014
241 Small Business Mexico Paseo 1607 300.00 482100.00 24105.00 457995.00 401750.00 56245.00 4/1/2014 4 April 2014
242 Government United States of America Paseo 2327 7.00 16289.00 814.45 15474.55 11635.00 3839.55 5/1/2014 5 May 2014
243 Small Business United States of America Paseo 991 300.00 297300.00 14865.00 282435.00 247750.00 34685.00 6/1/2014 6 June 2014
244 Government United States of America Paseo 602 350.00 210700.00 10535.00 200165.00 156520.00 43645.00 6/1/2014 6 June 2014
245 Midmarket France Paseo 2620 15.00 39300.00 1965.00 37335.00 26200.00 11135.00 9/1/2014 9 September 2014
246 Government Canada Paseo 1228 350.00 429800.00 21490.00 408310.00 319280.00 89030.00 10/1/2013 10 October 2013
247 Government Canada Paseo 1389 20.00 27780.00 1389.00 26391.00 13890.00 12501.00 10/1/2013 10 October 2013
248 Enterprise United States of America Paseo 861 125.00 107625.00 5381.25 102243.75 103320.00 -1076.25 10/1/2014 10 October 2014
249 Enterprise France Paseo 704 125.00 88000.00 4400.00 83600.00 84480.00 -880.00 10/1/2013 10 October 2013
250 Government Canada Paseo 1802 20.00 36040.00 1802.00 34238.00 18020.00 16218.00 12/1/2013 12 December 2013
251 Government United States of America Paseo 2663 20.00 53260.00 2663.00 50597.00 26630.00 23967.00 12/1/2014 12 December 2014
252 Government France Paseo 2136 7.00 14952.00 747.60 14204.40 10680.00 3524.40 12/1/2013 12 December 2013
253 Midmarket Germany Paseo 2116 15.00 31740.00 1587.00 30153.00 21160.00 8993.00 12/1/2013 12 December 2013
254 Midmarket United States of America Velo 555 15.00 8325.00 416.25 7908.75 5550.00 2358.75 1/1/2014 1 January 2014
255 Midmarket Mexico Velo 2861 15.00 42915.00 2145.75 40769.25 28610.00 12159.25 1/1/2014 1 January 2014
256 Enterprise Germany Velo 807 125.00 100875.00 5043.75 95831.25 96840.00 -1008.75 2/1/2014 2 February 2014
257 Government United States of America Velo 602 350.00 210700.00 10535.00 200165.00 156520.00 43645.00 6/1/2014 6 June 2014
258 Government United States of America Velo 2832 20.00 56640.00 2832.00 53808.00 28320.00 25488.00 8/1/2014 8 August 2014
259 Government France Velo 1579 20.00 31580.00 1579.00 30001.00 15790.00 14211.00 8/1/2014 8 August 2014
260 Enterprise United States of America Velo 861 125.00 107625.00 5381.25 102243.75 103320.00 -1076.25 10/1/2014 10 October 2014
261 Enterprise France Velo 704 125.00 88000.00 4400.00 83600.00 84480.00 -880.00 10/1/2013 10 October 2013
262 Government France Velo 1033 20.00 20660.00 1033.00 19627.00 10330.00 9297.00 12/1/2013 12 December 2013
263 Small Business Germany Velo 1250 300.00 375000.00 18750.00 356250.00 312500.00 43750.00 12/1/2014 12 December 2014
264 Government Canada VTT 1389 20.00 27780.00 1389.00 26391.00 13890.00 12501.00 10/1/2013 10 October 2013
265 Government United States of America VTT 1265 20.00 25300.00 1265.00 24035.00 12650.00 11385.00 11/1/2013 11 November 2013
266 Government Germany VTT 2297 20.00 45940.00 2297.00 43643.00 22970.00 20673.00 11/1/2013 11 November 2013
267 Government United States of America VTT 2663 20.00 53260.00 2663.00 50597.00 26630.00 23967.00 12/1/2014 12 December 2014
268 Government United States of America VTT 570 7.00 3990.00 199.50 3790.50 2850.00 940.50 12/1/2014 12 December 2014
269 Government France VTT 2487 7.00 17409.00 870.45 16538.55 12435.00 4103.55 12/1/2014 12 December 2014
270 Government Germany Amarilla 1350 350.00 472500.00 23625.00 448875.00 351000.00 97875.00 2/1/2014 2 February 2014
271 Government Canada Amarilla 552 350.00 193200.00 9660.00 183540.00 143520.00 40020.00 8/1/2014 8 August 2014
272 Government Canada Amarilla 1228 350.00 429800.00 21490.00 408310.00 319280.00 89030.00 10/1/2013 10 October 2013
273 Small Business Germany Amarilla 1250 300.00 375000.00 18750.00 356250.00 312500.00 43750.00 12/1/2014 12 December 2014
274 Midmarket France Paseo 3801 15.00 57015.00 3420.90 53594.10 38010.00 15584.10 4/1/2014 4 April 2014
275 Government United States of America Carretera 1117.5 20.00 22350.00 1341.00 21009.00 11175.00 9834.00 1/1/2014 1 January 2014
276 Midmarket Canada Carretera 2844 15.00 42660.00 2559.60 40100.40 28440.00 11660.40 6/1/2014 6 June 2014
277 Channel Partners Mexico Carretera 562 12.00 6744.00 404.64 6339.36 1686.00 4653.36 9/1/2014 9 September 2014
278 Channel Partners Canada Carretera 2299 12.00 27588.00 1655.28 25932.72 6897.00 19035.72 10/1/2013 10 October 2013
279 Midmarket United States of America Carretera 2030 15.00 30450.00 1827.00 28623.00 20300.00 8323.00 11/1/2014 11 November 2014
280 Government United States of America Carretera 263 7.00 1841.00 110.46 1730.54 1315.00 415.54 11/1/2013 11 November 2013
281 Enterprise Germany Carretera 887 125.00 110875.00 6652.50 104222.50 106440.00 -2217.50 12/1/2013 12 December 2013
282 Government Mexico Montana 980 350.00 343000.00 20580.00 322420.00 254800.00 67620.00 4/1/2014 4 April 2014
283 Government Germany Montana 1460 350.00 511000.00 30660.00 480340.00 379600.00 100740.00 5/1/2014 5 May 2014
284 Government France Montana 1403 7.00 9821.00 589.26 9231.74 7015.00 2216.74 10/1/2013 10 October 2013
285 Channel Partners United States of America Montana 2723 12.00 32676.00 1960.56 30715.44 8169.00 22546.44 11/1/2014 11 November 2014
286 Government France Paseo 1496 350.00 523600.00 31416.00 492184.00 388960.00 103224.00 6/1/2014 6 June 2014
287 Channel Partners Canada Paseo 2299 12.00 27588.00 1655.28 25932.72 6897.00 19035.72 10/1/2013 10 October 2013
288 Government United States of America Paseo 727 350.00 254450.00 15267.00 239183.00 189020.00 50163.00 10/1/2013 10 October 2013
289 Enterprise Canada Velo 952 125.00 119000.00 7140.00 111860.00 114240.00 -2380.00 2/1/2014 2 February 2014
290 Enterprise United States of America Velo 2755 125.00 344375.00 20662.50 323712.50 330600.00 -6887.50 2/1/2014 2 February 2014
291 Midmarket Germany Velo 1530 15.00 22950.00 1377.00 21573.00 15300.00 6273.00 5/1/2014 5 May 2014
292 Government France Velo 1496 350.00 523600.00 31416.00 492184.00 388960.00 103224.00 6/1/2014 6 June 2014
293 Government Mexico Velo 1498 7.00 10486.00 629.16 9856.84 7490.00 2366.84 6/1/2014 6 June 2014
294 Small Business France Velo 1221 300.00 366300.00 21978.00 344322.00 305250.00 39072.00 10/1/2013 10 October 2013
295 Government France Velo 2076 350.00 726600.00 43596.00 683004.00 539760.00 143244.00 10/1/2013 10 October 2013
296 Midmarket Canada VTT 2844 15.00 42660.00 2559.60 40100.40 28440.00 11660.40 6/1/2014 6 June 2014
297 Government Mexico VTT 1498 7.00 10486.00 629.16 9856.84 7490.00 2366.84 6/1/2014 6 June 2014
298 Small Business France VTT 1221 300.00 366300.00 21978.00 344322.00 305250.00 39072.00 10/1/2013 10 October 2013
299 Government Mexico VTT 1123 20.00 22460.00 1347.60 21112.40 11230.00 9882.40 11/1/2013 11 November 2013
300 Small Business Canada VTT 2436 300.00 730800.00 43848.00 686952.00 609000.00 77952.00 12/1/2013 12 December 2013
301 Enterprise France Amarilla 1987.5 125.00 248437.50 14906.25 233531.25 238500.00 -4968.75 1/1/2014 1 January 2014
302 Government Mexico Amarilla 1679 350.00 587650.00 35259.00 552391.00 436540.00 115851.00 9/1/2014 9 September 2014
303 Government United States of America Amarilla 727 350.00 254450.00 15267.00 239183.00 189020.00 50163.00 10/1/2013 10 October 2013
304 Government France Amarilla 1403 7.00 9821.00 589.26 9231.74 7015.00 2216.74 10/1/2013 10 October 2013
305 Government France Amarilla 2076 350.00 726600.00 43596.00 683004.00 539760.00 143244.00 10/1/2013 10 October 2013
306 Government France Montana 1757 20.00 35140.00 2108.40 33031.60 17570.00 15461.60 10/1/2013 10 October 2013
307 Midmarket United States of America Paseo 2198 15.00 32970.00 1978.20 30991.80 21980.00 9011.80 8/1/2014 8 August 2014
308 Midmarket Germany Paseo 1743 15.00 26145.00 1568.70 24576.30 17430.00 7146.30 8/1/2014 8 August 2014
309 Midmarket United States of America Paseo 1153 15.00 17295.00 1037.70 16257.30 11530.00 4727.30 10/1/2014 10 October 2014
310 Government France Paseo 1757 20.00 35140.00 2108.40 33031.60 17570.00 15461.60 10/1/2013 10 October 2013
311 Government Germany Velo 1001 20.00 20020.00 1201.20 18818.80 10010.00 8808.80 8/1/2014 8 August 2014
312 Government Mexico Velo 1333 7.00 9331.00 559.86 8771.14 6665.00 2106.14 11/1/2014 11 November 2014
313 Midmarket United States of America VTT 1153 15.00 17295.00 1037.70 16257.30 11530.00 4727.30 10/1/2014 10 October 2014
314 Channel Partners Mexico Carretera 727 12.00 8724.00 610.68 8113.32 2181.00 5932.32 2/1/2014 2 February 2014
315 Channel Partners Canada Carretera 1884 12.00 22608.00 1582.56 21025.44 5652.00 15373.44 8/1/2014 8 August 2014
316 Government Mexico Carretera 1834 20.00 36680.00 2567.60 34112.40 18340.00 15772.40 9/1/2013 9 September 2013
317 Channel Partners Mexico Montana 2340 12.00 28080.00 1965.60 26114.40 7020.00 19094.40 1/1/2014 1 January 2014
318 Channel Partners France Montana 2342 12.00 28104.00 1967.28 26136.72 7026.00 19110.72 11/1/2014 11 November 2014
319 Government France Paseo 1031 7.00 7217.00 505.19 6711.81 5155.00 1556.81 9/1/2013 9 September 2013
320 Midmarket Canada Velo 1262 15.00 18930.00 1325.10 17604.90 12620.00 4984.90 5/1/2014 5 May 2014
321 Government Canada Velo 1135 7.00 7945.00 556.15 7388.85 5675.00 1713.85 6/1/2014 6 June 2014
322 Government United States of America Velo 547 7.00 3829.00 268.03 3560.97 2735.00 825.97 11/1/2014 11 November 2014
323 Government Canada Velo 1582 7.00 11074.00 775.18 10298.82 7910.00 2388.82 12/1/2014 12 December 2014
324 Channel Partners France VTT 1738.5 12.00 20862.00 1460.34 19401.66 5215.50 14186.16 4/1/2014 4 April 2014
325 Channel Partners Germany VTT 2215 12.00 26580.00 1860.60 24719.40 6645.00 18074.40 9/1/2013 9 September 2013
326 Government Canada VTT 1582 7.00 11074.00 775.18 10298.82 7910.00 2388.82 12/1/2014 12 December 2014
327 Government Canada Amarilla 1135 7.00 7945.00 556.15 7388.85 5675.00 1713.85 6/1/2014 6 June 2014
328 Government United States of America Carretera 1761 350.00 616350.00 43144.50 573205.50 457860.00 115345.50 3/1/2014 3 March 2014
329 Small Business France Carretera 448 300.00 134400.00 9408.00 124992.00 112000.00 12992.00 6/1/2014 6 June 2014
330 Small Business France Carretera 2181 300.00 654300.00 45801.00 608499.00 545250.00 63249.00 10/1/2014 10 October 2014
331 Government France Montana 1976 20.00 39520.00 2766.40 36753.60 19760.00 16993.60 10/1/2014 10 October 2014
332 Small Business France Montana 2181 300.00 654300.00 45801.00 608499.00 545250.00 63249.00 10/1/2014 10 October 2014
333 Enterprise Germany Montana 2500 125.00 312500.00 21875.00 290625.00 300000.00 -9375.00 11/1/2013 11 November 2013
334 Small Business Canada Paseo 1702 300.00 510600.00 35742.00 474858.00 425500.00 49358.00 5/1/2014 5 May 2014
335 Small Business France Paseo 448 300.00 134400.00 9408.00 124992.00 112000.00 12992.00 6/1/2014 6 June 2014
336 Enterprise Germany Paseo 3513 125.00 439125.00 30738.75 408386.25 421560.00 -13173.75 7/1/2014 7 July 2014
337 Midmarket France Paseo 2101 15.00 31515.00 2206.05 29308.95 21010.00 8298.95 8/1/2014 8 August 2014
338 Midmarket United States of America Paseo 2931 15.00 43965.00 3077.55 40887.45 29310.00 11577.45 9/1/2013 9 September 2013
339 Government France Paseo 1535 20.00 30700.00 2149.00 28551.00 15350.00 13201.00 9/1/2014 9 September 2014
340 Small Business Germany Paseo 1123 300.00 336900.00 23583.00 313317.00 280750.00 32567.00 9/1/2013 9 September 2013
341 Small Business Canada Paseo 1404 300.00 421200.00 29484.00 391716.00 351000.00 40716.00 11/1/2013 11 November 2013
342 Channel Partners Mexico Paseo 2763 12.00 33156.00 2320.92 30835.08 8289.00 22546.08 11/1/2013 11 November 2013
343 Government Germany Paseo 2125 7.00 14875.00 1041.25 13833.75 10625.00 3208.75 12/1/2013 12 December 2013
344 Small Business France Velo 1659 300.00 497700.00 34839.00 462861.00 414750.00 48111.00 7/1/2014 7 July 2014
345 Government Mexico Velo 609 20.00 12180.00 852.60 11327.40 6090.00 5237.40 8/1/2014 8 August 2014
346 Enterprise Germany Velo 2087 125.00 260875.00 18261.25 242613.75 250440.00 -7826.25 9/1/2014 9 September 2014
347 Government France Velo 1976 20.00 39520.00 2766.40 36753.60 19760.00 16993.60 10/1/2014 10 October 2014
348 Government United States of America Velo 1421 20.00 28420.00 1989.40 26430.60 14210.00 12220.60 12/1/2013 12 December 2013
349 Small Business United States of America Velo 1372 300.00 411600.00 28812.00 382788.00 343000.00 39788.00 12/1/2014 12 December 2014
350 Government Germany Velo 588 20.00 11760.00 823.20 10936.80 5880.00 5056.80 12/1/2013 12 December 2013
351 Channel Partners Canada VTT 3244.5 12.00 38934.00 2725.38 36208.62 9733.50 26475.12 1/1/2014 1 January 2014
352 Small Business France VTT 959 300.00 287700.00 20139.00 267561.00 239750.00 27811.00 2/1/2014 2 February 2014
353 Small Business Mexico VTT 2747 300.00 824100.00 57687.00 766413.00 686750.00 79663.00 2/1/2014 2 February 2014
354 Enterprise Canada Amarilla 1645 125.00 205625.00 14393.75 191231.25 197400.00 -6168.75 5/1/2014 5 May 2014
355 Government France Amarilla 2876 350.00 1006600.00 70462.00 936138.00 747760.00 188378.00 9/1/2014 9 September 2014
356 Enterprise Germany Amarilla 994 125.00 124250.00 8697.50 115552.50 119280.00 -3727.50 9/1/2013 9 September 2013
357 Government Canada Amarilla 1118 20.00 22360.00 1565.20 20794.80 11180.00 9614.80 11/1/2014 11 November 2014
358 Small Business United States of America Amarilla 1372 300.00 411600.00 28812.00 382788.00 343000.00 39788.00 12/1/2014 12 December 2014
359 Government Canada Montana 488 7.00 3416.00 273.28 3142.72 2440.00 702.72 2/1/2014 2 February 2014
360 Government United States of America Montana 1282 20.00 25640.00 2051.20 23588.80 12820.00 10768.80 6/1/2014 6 June 2014
361 Government Canada Paseo 257 7.00 1799.00 143.92 1655.08 1285.00 370.08 5/1/2014 5 May 2014
362 Government United States of America Amarilla 1282 20.00 25640.00 2051.20 23588.80 12820.00 10768.80 6/1/2014 6 June 2014
363 Enterprise Mexico Carretera 1540 125.00 192500.00 15400.00 177100.00 184800.00 -7700.00 8/1/2014 8 August 2014
364 Midmarket France Carretera 490 15.00 7350.00 588.00 6762.00 4900.00 1862.00 11/1/2014 11 November 2014
365 Government Mexico Carretera 1362 350.00 476700.00 38136.00 438564.00 354120.00 84444.00 12/1/2014 12 December 2014
366 Midmarket France Montana 2501 15.00 37515.00 3001.20 34513.80 25010.00 9503.80 3/1/2014 3 March 2014
367 Government Canada Montana 708 20.00 14160.00 1132.80 13027.20 7080.00 5947.20 6/1/2014 6 June 2014
368 Government Germany Montana 645 20.00 12900.00 1032.00 11868.00 6450.00 5418.00 7/1/2014 7 July 2014
369 Small Business France Montana 1562 300.00 468600.00 37488.00 431112.00 390500.00 40612.00 8/1/2014 8 August 2014
370 Small Business Canada Montana 1283 300.00 384900.00 30792.00 354108.00 320750.00 33358.00 9/1/2013 9 September 2013
371 Midmarket Germany Montana 711 15.00 10665.00 853.20 9811.80 7110.00 2701.80 12/1/2014 12 December 2014
372 Enterprise Mexico Paseo 1114 125.00 139250.00 11140.00 128110.00 133680.00 -5570.00 3/1/2014 3 March 2014
373 Government Germany Paseo 1259 7.00 8813.00 705.04 8107.96 6295.00 1812.96 4/1/2014 4 April 2014
374 Government Germany Paseo 1095 7.00 7665.00 613.20 7051.80 5475.00 1576.80 5/1/2014 5 May 2014
375 Government Germany Paseo 1366 20.00 27320.00 2185.60 25134.40 13660.00 11474.40 6/1/2014 6 June 2014
376 Small Business Mexico Paseo 2460 300.00 738000.00 59040.00 678960.00 615000.00 63960.00 6/1/2014 6 June 2014
377 Government United States of America Paseo 678 7.00 4746.00 379.68 4366.32 3390.00 976.32 8/1/2014 8 August 2014
378 Government Germany Paseo 1598 7.00 11186.00 894.88 10291.12 7990.00 2301.12 8/1/2014 8 August 2014
379 Government Germany Paseo 2409 7.00 16863.00 1349.04 15513.96 12045.00 3468.96 9/1/2013 9 September 2013
380 Government Germany Paseo 1934 20.00 38680.00 3094.40 35585.60 19340.00 16245.60 9/1/2014 9 September 2014
381 Government Mexico Paseo 2993 20.00 59860.00 4788.80 55071.20 29930.00 25141.20 9/1/2014 9 September 2014
382 Government Germany Paseo 2146 350.00 751100.00 60088.00 691012.00 557960.00 133052.00 11/1/2013 11 November 2013
383 Government Mexico Paseo 1946 7.00 13622.00 1089.76 12532.24 9730.00 2802.24 12/1/2013 12 December 2013
384 Government Mexico Paseo 1362 350.00 476700.00 38136.00 438564.00 354120.00 84444.00 12/1/2014 12 December 2014
385 Channel Partners Canada Velo 598 12.00 7176.00 574.08 6601.92 1794.00 4807.92 3/1/2014 3 March 2014
386 Government United States of America Velo 2907 7.00 20349.00 1627.92 18721.08 14535.00 4186.08 6/1/2014 6 June 2014
387 Government Germany Velo 2338 7.00 16366.00 1309.28 15056.72 11690.00 3366.72 6/1/2014 6 June 2014
388 Small Business France Velo 386 300.00 115800.00 9264.00 106536.00 96500.00 10036.00 11/1/2013 11 November 2013
389 Small Business Mexico Velo 635 300.00 190500.00 15240.00 175260.00 158750.00 16510.00 12/1/2014 12 December 2014
390 Government France VTT 574.5 350.00 201075.00 16086.00 184989.00 149370.00 35619.00 4/1/2014 4 April 2014
391 Government Germany VTT 2338 7.00 16366.00 1309.28 15056.72 11690.00 3366.72 6/1/2014 6 June 2014
392 Government France VTT 381 350.00 133350.00 10668.00 122682.00 99060.00 23622.00 8/1/2014 8 August 2014
393 Government Germany VTT 422 350.00 147700.00 11816.00 135884.00 109720.00 26164.00 8/1/2014 8 August 2014
394 Small Business Canada VTT 2134 300.00 640200.00 51216.00 588984.00 533500.00 55484.00 9/1/2014 9 September 2014
395 Small Business United States of America VTT 808 300.00 242400.00 19392.00 223008.00 202000.00 21008.00 12/1/2013 12 December 2013
396 Government Canada Amarilla 708 20.00 14160.00 1132.80 13027.20 7080.00 5947.20 6/1/2014 6 June 2014
397 Government United States of America Amarilla 2907 7.00 20349.00 1627.92 18721.08 14535.00 4186.08 6/1/2014 6 June 2014
398 Government Germany Amarilla 1366 20.00 27320.00 2185.60 25134.40 13660.00 11474.40 6/1/2014 6 June 2014
399 Small Business Mexico Amarilla 2460 300.00 738000.00 59040.00 678960.00 615000.00 63960.00 6/1/2014 6 June 2014
400 Government Germany Amarilla 1520 20.00 30400.00 2432.00 27968.00 15200.00 12768.00 11/1/2014 11 November 2014
401 Midmarket Germany Amarilla 711 15.00 10665.00 853.20 9811.80 7110.00 2701.80 12/1/2014 12 December 2014
402 Channel Partners Mexico Amarilla 1375 12.00 16500.00 1320.00 15180.00 4125.00 11055.00 12/1/2013 12 December 2013
403 Small Business Mexico Amarilla 635 300.00 190500.00 15240.00 175260.00 158750.00 16510.00 12/1/2014 12 December 2014
404 Government United States of America VTT 436.5 20.00 8730.00 698.40 8031.60 4365.00 3666.60 7/1/2014 7 July 2014
405 Small Business Canada Carretera 1094 300.00 328200.00 29538.00 298662.00 273500.00 25162.00 6/1/2014 6 June 2014
406 Channel Partners Mexico Carretera 367 12.00 4404.00 396.36 4007.64 1101.00 2906.64 10/1/2013 10 October 2013
407 Small Business Canada Montana 3802.5 300.00 1140750.00 102667.50 1038082.50 950625.00 87457.50 4/1/2014 4 April 2014
408 Government France Montana 1666 350.00 583100.00 52479.00 530621.00 433160.00 97461.00 5/1/2014 5 May 2014
409 Small Business France Montana 322 300.00 96600.00 8694.00 87906.00 80500.00 7406.00 9/1/2013 9 September 2013
410 Channel Partners Canada Montana 2321 12.00 27852.00 2506.68 25345.32 6963.00 18382.32 11/1/2014 11 November 2014
411 Enterprise France Montana 1857 125.00 232125.00 20891.25 211233.75 222840.00 -11606.25 11/1/2013 11 November 2013
412 Government Canada Montana 1611 7.00 11277.00 1014.93 10262.07 8055.00 2207.07 12/1/2013 12 December 2013
413 Enterprise United States of America Montana 2797 125.00 349625.00 31466.25 318158.75 335640.00 -17481.25 12/1/2014 12 December 2014
414 Small Business Germany Montana 334 300.00 100200.00 9018.00 91182.00 83500.00 7682.00 12/1/2013 12 December 2013
415 Small Business Mexico Paseo 2565 300.00 769500.00 69255.00 700245.00 641250.00 58995.00 1/1/2014 1 January 2014
416 Government Mexico Paseo 2417 350.00 845950.00 76135.50 769814.50 628420.00 141394.50 1/1/2014 1 January 2014
417 Midmarket United States of America Paseo 3675 15.00 55125.00 4961.25 50163.75 36750.00 13413.75 4/1/2014 4 April 2014
418 Small Business Canada Paseo 1094 300.00 328200.00 29538.00 298662.00 273500.00 25162.00 6/1/2014 6 June 2014
419 Midmarket France Paseo 1227 15.00 18405.00 1656.45 16748.55 12270.00 4478.55 10/1/2014 10 October 2014
420 Channel Partners Mexico Paseo 367 12.00 4404.00 396.36 4007.64 1101.00 2906.64 10/1/2013 10 October 2013
421 Small Business France Paseo 1324 300.00 397200.00 35748.00 361452.00 331000.00 30452.00 11/1/2014 11 November 2014
422 Channel Partners Germany Paseo 1775 12.00 21300.00 1917.00 19383.00 5325.00 14058.00 11/1/2013 11 November 2013
423 Enterprise United States of America Paseo 2797 125.00 349625.00 31466.25 318158.75 335640.00 -17481.25 12/1/2014 12 December 2014
424 Midmarket Mexico Velo 245 15.00 3675.00 330.75 3344.25 2450.00 894.25 5/1/2014 5 May 2014
425 Small Business Canada Velo 3793.5 300.00 1138050.00 102424.50 1035625.50 948375.00 87250.50 7/1/2014 7 July 2014
426 Government Germany Velo 1307 350.00 457450.00 41170.50 416279.50 339820.00 76459.50 7/1/2014 7 July 2014
427 Enterprise Canada Velo 567 125.00 70875.00 6378.75 64496.25 68040.00 -3543.75 9/1/2014 9 September 2014
428 Enterprise Mexico Velo 2110 125.00 263750.00 23737.50 240012.50 253200.00 -13187.50 9/1/2014 9 September 2014
429 Government Canada Velo 1269 350.00 444150.00 39973.50 404176.50 329940.00 74236.50 10/1/2014 10 October 2014
430 Channel Partners United States of America VTT 1956 12.00 23472.00 2112.48 21359.52 5868.00 15491.52 1/1/2014 1 January 2014
431 Small Business Germany VTT 2659 300.00 797700.00 71793.00 725907.00 664750.00 61157.00 2/1/2014 2 February 2014
432 Government United States of America VTT 1351.5 350.00 473025.00 42572.25 430452.75 351390.00 79062.75 4/1/2014 4 April 2014
433 Channel Partners Germany VTT 880 12.00 10560.00 950.40 9609.60 2640.00 6969.60 5/1/2014 5 May 2014
434 Small Business United States of America VTT 1867 300.00 560100.00 50409.00 509691.00 466750.00 42941.00 9/1/2014 9 September 2014
435 Channel Partners France VTT 2234 12.00 26808.00 2412.72 24395.28 6702.00 17693.28 9/1/2013 9 September 2013
436 Midmarket France VTT 1227 15.00 18405.00 1656.45 16748.55 12270.00 4478.55 10/1/2014 10 October 2014
437 Enterprise Mexico VTT 877 125.00 109625.00 9866.25 99758.75 105240.00 -5481.25 11/1/2014 11 November 2014
438 Government United States of America Amarilla 2071 350.00 724850.00 65236.50 659613.50 538460.00 121153.50 9/1/2014 9 September 2014
439 Government Canada Amarilla 1269 350.00 444150.00 39973.50 404176.50 329940.00 74236.50 10/1/2014 10 October 2014
440 Midmarket Germany Amarilla 970 15.00 14550.00 1309.50 13240.50 9700.00 3540.50 11/1/2013 11 November 2013
441 Government Mexico Amarilla 1694 20.00 33880.00 3049.20 30830.80 16940.00 13890.80 11/1/2014 11 November 2014
442 Government Germany Carretera 663 20.00 13260.00 1193.40 12066.60 6630.00 5436.60 5/1/2014 5 May 2014
443 Government Canada Carretera 819 7.00 5733.00 515.97 5217.03 4095.00 1122.03 7/1/2014 7 July 2014
444 Channel Partners Germany Carretera 1580 12.00 18960.00 1706.40 17253.60 4740.00 12513.60 9/1/2014 9 September 2014
445 Government Mexico Carretera 521 7.00 3647.00 328.23 3318.77 2605.00 713.77 12/1/2014 12 December 2014
446 Government United States of America Paseo 973 20.00 19460.00 1751.40 17708.60 9730.00 7978.60 3/1/2014 3 March 2014
447 Government Mexico Paseo 1038 20.00 20760.00 1868.40 18891.60 10380.00 8511.60 6/1/2014 6 June 2014
448 Government Germany Paseo 360 7.00 2520.00 226.80 2293.20 1800.00 493.20 10/1/2014 10 October 2014
449 Channel Partners France Velo 1967 12.00 23604.00 2124.36 21479.64 5901.00 15578.64 3/1/2014 3 March 2014
450 Midmarket Mexico Velo 2628 15.00 39420.00 3547.80 35872.20 26280.00 9592.20 4/1/2014 4 April 2014
451 Government Germany VTT 360 7.00 2520.00 226.80 2293.20 1800.00 493.20 10/1/2014 10 October 2014
452 Government France VTT 2682 20.00 53640.00 4827.60 48812.40 26820.00 21992.40 11/1/2013 11 November 2013
453 Government Mexico VTT 521 7.00 3647.00 328.23 3318.77 2605.00 713.77 12/1/2014 12 December 2014
454 Government Mexico Amarilla 1038 20.00 20760.00 1868.40 18891.60 10380.00 8511.60 6/1/2014 6 June 2014
455 Midmarket Canada Amarilla 1630.5 15.00 24457.50 2201.18 22256.33 16305.00 5951.33 7/1/2014 7 July 2014
456 Channel Partners France Amarilla 306 12.00 3672.00 330.48 3341.52 918.00 2423.52 12/1/2013 12 December 2013
457 Channel Partners United States of America Carretera 386 12.00 4632.00 463.20 4168.80 1158.00 3010.80 10/1/2013 10 October 2013
458 Government United States of America Montana 2328 7.00 16296.00 1629.60 14666.40 11640.00 3026.40 9/1/2014 9 September 2014
459 Channel Partners United States of America Paseo 386 12.00 4632.00 463.20 4168.80 1158.00 3010.80 10/1/2013 10 October 2013
460 Enterprise United States of America Carretera 3445.5 125.00 430687.50 43068.75 387618.75 413460.00 -25841.25 4/1/2014 4 April 2014
461 Enterprise France Carretera 1482 125.00 185250.00 18525.00 166725.00 177840.00 -11115.00 12/1/2013 12 December 2013
462 Government United States of America Montana 2313 350.00 809550.00 80955.00 728595.00 601380.00 127215.00 5/1/2014 5 May 2014
463 Enterprise United States of America Montana 1804 125.00 225500.00 22550.00 202950.00 216480.00 -13530.00 11/1/2013 11 November 2013
464 Midmarket France Montana 2072 15.00 31080.00 3108.00 27972.00 20720.00 7252.00 12/1/2014 12 December 2014
465 Government France Paseo 1954 20.00 39080.00 3908.00 35172.00 19540.00 15632.00 3/1/2014 3 March 2014
466 Small Business Mexico Paseo 591 300.00 177300.00 17730.00 159570.00 147750.00 11820.00 5/1/2014 5 May 2014
467 Midmarket France Paseo 2167 15.00 32505.00 3250.50 29254.50 21670.00 7584.50 10/1/2013 10 October 2013
468 Government Germany Paseo 241 20.00 4820.00 482.00 4338.00 2410.00 1928.00 10/1/2014 10 October 2014
469 Midmarket Germany Velo 681 15.00 10215.00 1021.50 9193.50 6810.00 2383.50 1/1/2014 1 January 2014
470 Midmarket Germany Velo 510 15.00 7650.00 765.00 6885.00 5100.00 1785.00 4/1/2014 4 April 2014
471 Midmarket United States of America Velo 790 15.00 11850.00 1185.00 10665.00 7900.00 2765.00 5/1/2014 5 May 2014
472 Government France Velo 639 350.00 223650.00 22365.00 201285.00 166140.00 35145.00 7/1/2014 7 July 2014
473 Enterprise United States of America Velo 1596 125.00 199500.00 19950.00 179550.00 191520.00 -11970.00 9/1/2014 9 September 2014
474 Small Business United States of America Velo 2294 300.00 688200.00 68820.00 619380.00 573500.00 45880.00 10/1/2013 10 October 2013
475 Government Germany Velo 241 20.00 4820.00 482.00 4338.00 2410.00 1928.00 10/1/2014 10 October 2014
476 Government Germany Velo 2665 7.00 18655.00 1865.50 16789.50 13325.00 3464.50 11/1/2014 11 November 2014
477 Enterprise Canada Velo 1916 125.00 239500.00 23950.00 215550.00 229920.00 -14370.00 12/1/2013 12 December 2013
478 Small Business France Velo 853 300.00 255900.00 25590.00 230310.00 213250.00 17060.00 12/1/2014 12 December 2014
479 Enterprise Mexico VTT 341 125.00 42625.00 4262.50 38362.50 40920.00 -2557.50 5/1/2014 5 May 2014
480 Midmarket Mexico VTT 641 15.00 9615.00 961.50 8653.50 6410.00 2243.50 7/1/2014 7 July 2014
481 Government United States of America VTT 2807 350.00 982450.00 98245.00 884205.00 729820.00 154385.00 8/1/2014 8 August 2014
482 Small Business Mexico VTT 432 300.00 129600.00 12960.00 116640.00 108000.00 8640.00 9/1/2014 9 September 2014
483 Small Business United States of America VTT 2294 300.00 688200.00 68820.00 619380.00 573500.00 45880.00 10/1/2013 10 October 2013
484 Midmarket France VTT 2167 15.00 32505.00 3250.50 29254.50 21670.00 7584.50 10/1/2013 10 October 2013
485 Enterprise Canada VTT 2529 125.00 316125.00 31612.50 284512.50 303480.00 -18967.50 11/1/2014 11 November 2014
486 Government Germany VTT 1870 350.00 654500.00 65450.00 589050.00 486200.00 102850.00 12/1/2013 12 December 2013
487 Enterprise United States of America Amarilla 579 125.00 72375.00 7237.50 65137.50 69480.00 -4342.50 1/1/2014 1 January 2014
488 Government Canada Amarilla 2240 350.00 784000.00 78400.00 705600.00 582400.00 123200.00 2/1/2014 2 February 2014
489 Small Business United States of America Amarilla 2993 300.00 897900.00 89790.00 808110.00 748250.00 59860.00 3/1/2014 3 March 2014
490 Channel Partners Canada Amarilla 3520.5 12.00 42246.00 4224.60 38021.40 10561.50 27459.90 4/1/2014 4 April 2014
491 Government Mexico Amarilla 2039 20.00 40780.00 4078.00 36702.00 20390.00 16312.00 5/1/2014 5 May 2014
492 Channel Partners Germany Amarilla 2574 12.00 30888.00 3088.80 27799.20 7722.00 20077.20 8/1/2014 8 August 2014
493 Government Canada Amarilla 707 350.00 247450.00 24745.00 222705.00 183820.00 38885.00 9/1/2014 9 September 2014
494 Midmarket France Amarilla 2072 15.00 31080.00 3108.00 27972.00 20720.00 7252.00 12/1/2014 12 December 2014
495 Small Business France Amarilla 853 300.00 255900.00 25590.00 230310.00 213250.00 17060.00 12/1/2014 12 December 2014
496 Channel Partners France Carretera 1198 12.00 14376.00 1581.36 12794.64 3594.00 9200.64 10/1/2013 10 October 2013
497 Government France Paseo 2532 7.00 17724.00 1949.64 15774.36 12660.00 3114.36 4/1/2014 4 April 2014
498 Channel Partners France Paseo 1198 12.00 14376.00 1581.36 12794.64 3594.00 9200.64 10/1/2013 10 October 2013
499 Midmarket Canada Velo 384 15.00 5760.00 633.60 5126.40 3840.00 1286.40 1/1/2014 1 January 2014
500 Channel Partners Germany Velo 472 12.00 5664.00 623.04 5040.96 1416.00 3624.96 10/1/2014 10 October 2014
501 Government United States of America VTT 1579 7.00 11053.00 1215.83 9837.17 7895.00 1942.17 3/1/2014 3 March 2014
502 Channel Partners Mexico VTT 1005 12.00 12060.00 1326.60 10733.40 3015.00 7718.40 9/1/2013 9 September 2013
503 Midmarket United States of America Amarilla 3199.5 15.00 47992.50 5279.18 42713.33 31995.00 10718.33 7/1/2014 7 July 2014
504 Channel Partners Germany Amarilla 472 12.00 5664.00 623.04 5040.96 1416.00 3624.96 10/1/2014 10 October 2014
505 Channel Partners Canada Carretera 1937 12.00 23244.00 2556.84 20687.16 5811.00 14876.16 2/1/2014 2 February 2014
506 Government Germany Carretera 792 350.00 277200.00 30492.00 246708.00 205920.00 40788.00 3/1/2014 3 March 2014
507 Small Business Germany Carretera 2811 300.00 843300.00 92763.00 750537.00 702750.00 47787.00 7/1/2014 7 July 2014
508 Enterprise France Carretera 2441 125.00 305125.00 33563.75 271561.25 292920.00 -21358.75 10/1/2014 10 October 2014
509 Midmarket Canada Carretera 1560 15.00 23400.00 2574.00 20826.00 15600.00 5226.00 11/1/2013 11 November 2013
510 Government Mexico Carretera 2706 7.00 18942.00 2083.62 16858.38 13530.00 3328.38 11/1/2013 11 November 2013
511 Government Germany Montana 766 350.00 268100.00 29491.00 238609.00 199160.00 39449.00 1/1/2014 1 January 2014
512 Government Germany Montana 2992 20.00 59840.00 6582.40 53257.60 29920.00 23337.60 10/1/2013 10 October 2013
513 Midmarket Mexico Montana 2157 15.00 32355.00 3559.05 28795.95 21570.00 7225.95 12/1/2014 12 December 2014
514 Small Business Canada Paseo 873 300.00 261900.00 28809.00 233091.00 218250.00 14841.00 1/1/2014 1 January 2014
515 Government Mexico Paseo 1122 20.00 22440.00 2468.40 19971.60 11220.00 8751.60 3/1/2014 3 March 2014
516 Government Canada Paseo 2104.5 350.00 736575.00 81023.25 655551.75 547170.00 108381.75 7/1/2014 7 July 2014
517 Channel Partners Canada Paseo 4026 12.00 48312.00 5314.32 42997.68 12078.00 30919.68 7/1/2014 7 July 2014
518 Channel Partners France Paseo 2425.5 12.00 29106.00 3201.66 25904.34 7276.50 18627.84 7/1/2014 7 July 2014
519 Government Canada Paseo 2394 20.00 47880.00 5266.80 42613.20 23940.00 18673.20 8/1/2014 8 August 2014
520 Midmarket Mexico Paseo 1984 15.00 29760.00 3273.60 26486.40 19840.00 6646.40 8/1/2014 8 August 2014
521 Enterprise France Paseo 2441 125.00 305125.00 33563.75 271561.25 292920.00 -21358.75 10/1/2014 10 October 2014
522 Government Germany Paseo 2992 20.00 59840.00 6582.40 53257.60 29920.00 23337.60 10/1/2013 10 October 2013
523 Small Business Canada Paseo 1366 300.00 409800.00 45078.00 364722.00 341500.00 23222.00 11/1/2014 11 November 2014
524 Government France Velo 2805 20.00 56100.00 6171.00 49929.00 28050.00 21879.00 9/1/2013 9 September 2013
525 Midmarket Mexico Velo 655 15.00 9825.00 1080.75 8744.25 6550.00 2194.25 9/1/2013 9 September 2013
526 Government Mexico Velo 344 350.00 120400.00 13244.00 107156.00 89440.00 17716.00 10/1/2013 10 October 2013
527 Government Canada Velo 1808 7.00 12656.00 1392.16 11263.84 9040.00 2223.84 11/1/2014 11 November 2014
528 Channel Partners France VTT 1734 12.00 20808.00 2288.88 18519.12 5202.00 13317.12 1/1/2014 1 January 2014
529 Enterprise Mexico VTT 554 125.00 69250.00 7617.50 61632.50 66480.00 -4847.50 1/1/2014 1 January 2014
530 Government Canada VTT 2935 20.00 58700.00 6457.00 52243.00 29350.00 22893.00 11/1/2013 11 November 2013
531 Enterprise Germany Amarilla 3165 125.00 395625.00 43518.75 352106.25 379800.00 -27693.75 1/1/2014 1 January 2014
532 Government Mexico Amarilla 2629 20.00 52580.00 5783.80 46796.20 26290.00 20506.20 1/1/2014 1 January 2014
533 Enterprise France Amarilla 1433 125.00 179125.00 19703.75 159421.25 171960.00 -12538.75 5/1/2014 5 May 2014
534 Enterprise Mexico Amarilla 947 125.00 118375.00 13021.25 105353.75 113640.00 -8286.25 9/1/2013 9 September 2013
535 Government Mexico Amarilla 344 350.00 120400.00 13244.00 107156.00 89440.00 17716.00 10/1/2013 10 October 2013
536 Midmarket Mexico Amarilla 2157 15.00 32355.00 3559.05 28795.95 21570.00 7225.95 12/1/2014 12 December 2014
537 Government United States of America Paseo 380 7.00 2660.00 292.60 2367.40 1900.00 467.40 9/1/2013 9 September 2013
538 Government Mexico Carretera 886 350.00 310100.00 37212.00 272888.00 230360.00 42528.00 6/1/2014 6 June 2014
539 Enterprise Canada Carretera 2416 125.00 302000.00 36240.00 265760.00 289920.00 -24160.00 9/1/2013 9 September 2013
540 Enterprise Mexico Carretera 2156 125.00 269500.00 32340.00 237160.00 258720.00 -21560.00 10/1/2014 10 October 2014
541 Midmarket Canada Carretera 2689 15.00 40335.00 4840.20 35494.80 26890.00 8604.80 11/1/2014 11 November 2014
542 Midmarket United States of America Montana 677 15.00 10155.00 1218.60 8936.40 6770.00 2166.40 3/1/2014 3 March 2014
543 Small Business France Montana 1773 300.00 531900.00 63828.00 468072.00 443250.00 24822.00 4/1/2014 4 April 2014
544 Government Mexico Montana 2420 7.00 16940.00 2032.80 14907.20 12100.00 2807.20 9/1/2014 9 September 2014
545 Government Canada Montana 2734 7.00 19138.00 2296.56 16841.44 13670.00 3171.44 10/1/2014 10 October 2014
546 Government Mexico Montana 1715 20.00 34300.00 4116.00 30184.00 17150.00 13034.00 10/1/2013 10 October 2013
547 Small Business France Montana 1186 300.00 355800.00 42696.00 313104.00 296500.00 16604.00 12/1/2013 12 December 2013
548 Small Business United States of America Paseo 3495 300.00 1048500.00 125820.00 922680.00 873750.00 48930.00 1/1/2014 1 January 2014
549 Government Mexico Paseo 886 350.00 310100.00 37212.00 272888.00 230360.00 42528.00 6/1/2014 6 June 2014
550 Enterprise Mexico Paseo 2156 125.00 269500.00 32340.00 237160.00 258720.00 -21560.00 10/1/2014 10 October 2014
551 Government Mexico Paseo 905 20.00 18100.00 2172.00 15928.00 9050.00 6878.00 10/1/2014 10 October 2014
552 Government Mexico Paseo 1715 20.00 34300.00 4116.00 30184.00 17150.00 13034.00 10/1/2013 10 October 2013
553 Government France Paseo 1594 350.00 557900.00 66948.00 490952.00 414440.00 76512.00 11/1/2014 11 November 2014
554 Small Business Germany Paseo 1359 300.00 407700.00 48924.00 358776.00 339750.00 19026.00 11/1/2014 11 November 2014
555 Small Business Mexico Paseo 2150 300.00 645000.00 77400.00 567600.00 537500.00 30100.00 11/1/2014 11 November 2014
556 Government Mexico Paseo 1197 350.00 418950.00 50274.00 368676.00 311220.00 57456.00 11/1/2014 11 November 2014
557 Midmarket Mexico Paseo 380 15.00 5700.00 684.00 5016.00 3800.00 1216.00 12/1/2013 12 December 2013
558 Government Mexico Paseo 1233 20.00 24660.00 2959.20 21700.80 12330.00 9370.80 12/1/2014 12 December 2014
559 Government Mexico Velo 1395 350.00 488250.00 58590.00 429660.00 362700.00 66960.00 7/1/2014 7 July 2014
560 Government United States of America Velo 986 350.00 345100.00 41412.00 303688.00 256360.00 47328.00 10/1/2014 10 October 2014
561 Government Mexico Velo 905 20.00 18100.00 2172.00 15928.00 9050.00 6878.00 10/1/2014 10 October 2014
562 Channel Partners Canada VTT 2109 12.00 25308.00 3036.96 22271.04 6327.00 15944.04 5/1/2014 5 May 2014
563 Midmarket France VTT 3874.5 15.00 58117.50 6974.10 51143.40 38745.00 12398.40 7/1/2014 7 July 2014
564 Government Canada VTT 623 350.00 218050.00 26166.00 191884.00 161980.00 29904.00 9/1/2013 9 September 2013
565 Government United States of America VTT 986 350.00 345100.00 41412.00 303688.00 256360.00 47328.00 10/1/2014 10 October 2014
566 Enterprise United States of America VTT 2387 125.00 298375.00 35805.00 262570.00 286440.00 -23870.00 11/1/2014 11 November 2014
567 Government Mexico VTT 1233 20.00 24660.00 2959.20 21700.80 12330.00 9370.80 12/1/2014 12 December 2014
568 Government United States of America Amarilla 270 350.00 94500.00 11340.00 83160.00 70200.00 12960.00 2/1/2014 2 February 2014
569 Government France Amarilla 3421.5 7.00 23950.50 2874.06 21076.44 17107.50 3968.94 7/1/2014 7 July 2014
570 Government Canada Amarilla 2734 7.00 19138.00 2296.56 16841.44 13670.00 3171.44 10/1/2014 10 October 2014
571 Midmarket United States of America Amarilla 2548 15.00 38220.00 4586.40 33633.60 25480.00 8153.60 11/1/2013 11 November 2013
572 Government France Carretera 2521.5 20.00 50430.00 6051.60 44378.40 25215.00 19163.40 1/1/2014 1 January 2014
573 Channel Partners Mexico Montana 2661 12.00 31932.00 3831.84 28100.16 7983.00 20117.16 5/1/2014 5 May 2014
574 Government Germany Paseo 1531 20.00 30620.00 3674.40 26945.60 15310.00 11635.60 12/1/2014 12 December 2014
575 Government France VTT 1491 7.00 10437.00 1252.44 9184.56 7455.00 1729.56 3/1/2014 3 March 2014
576 Government Germany VTT 1531 20.00 30620.00 3674.40 26945.60 15310.00 11635.60 12/1/2014 12 December 2014
577 Channel Partners Canada Amarilla 2761 12.00 33132.00 3975.84 29156.16 8283.00 20873.16 9/1/2013 9 September 2013
578 Midmarket United States of America Carretera 2567 15.00 38505.00 5005.65 33499.35 25670.00 7829.35 6/1/2014 6 June 2014
579 Midmarket United States of America VTT 2567 15.00 38505.00 5005.65 33499.35 25670.00 7829.35 6/1/2014 6 June 2014
580 Government Canada Carretera 923 350.00 323050.00 41996.50 281053.50 239980.00 41073.50 3/1/2014 3 March 2014
581 Government France Carretera 1790 350.00 626500.00 81445.00 545055.00 465400.00 79655.00 3/1/2014 3 March 2014
582 Government Germany Carretera 442 20.00 8840.00 1149.20 7690.80 4420.00 3270.80 9/1/2013 9 September 2013
583 Government United States of America Montana 982.5 350.00 343875.00 44703.75 299171.25 255450.00 43721.25 1/1/2014 1 January 2014
584 Government United States of America Montana 1298 7.00 9086.00 1181.18 7904.82 6490.00 1414.82 2/1/2014 2 February 2014
585 Channel Partners Mexico Montana 604 12.00 7248.00 942.24 6305.76 1812.00 4493.76 6/1/2014 6 June 2014
586 Government Mexico Montana 2255 20.00 45100.00 5863.00 39237.00 22550.00 16687.00 7/1/2014 7 July 2014
587 Government Canada Montana 1249 20.00 24980.00 3247.40 21732.60 12490.00 9242.60 10/1/2014 10 October 2014
588 Government United States of America Paseo 1438.5 7.00 10069.50 1309.04 8760.47 7192.50 1567.97 1/1/2014 1 January 2014
589 Small Business Germany Paseo 807 300.00 242100.00 31473.00 210627.00 201750.00 8877.00 1/1/2014 1 January 2014
590 Government United States of America Paseo 2641 20.00 52820.00 6866.60 45953.40 26410.00 19543.40 2/1/2014 2 February 2014
591 Government Germany Paseo 2708 20.00 54160.00 7040.80 47119.20 27080.00 20039.20 2/1/2014 2 February 2014
592 Government Canada Paseo 2632 350.00 921200.00 119756.00 801444.00 684320.00 117124.00 6/1/2014 6 June 2014
593 Enterprise Canada Paseo 1583 125.00 197875.00 25723.75 172151.25 189960.00 -17808.75 6/1/2014 6 June 2014
594 Channel Partners Mexico Paseo 571 12.00 6852.00 890.76 5961.24 1713.00 4248.24 7/1/2014 7 July 2014
595 Government France Paseo 2696 7.00 18872.00 2453.36 16418.64 13480.00 2938.64 8/1/2014 8 August 2014
596 Midmarket Canada Paseo 1565 15.00 23475.00 3051.75 20423.25 15650.00 4773.25 10/1/2014 10 October 2014
597 Government Canada Paseo 1249 20.00 24980.00 3247.40 21732.60 12490.00 9242.60 10/1/2014 10 October 2014
598 Government Germany Paseo 357 350.00 124950.00 16243.50 108706.50 92820.00 15886.50 11/1/2014 11 November 2014
599 Channel Partners Germany Paseo 1013 12.00 12156.00 1580.28 10575.72 3039.00 7536.72 12/1/2014 12 December 2014
600 Midmarket France Velo 3997.5 15.00 59962.50 7795.13 52167.38 39975.00 12192.38 1/1/2014 1 January 2014
601 Government Canada Velo 2632 350.00 921200.00 119756.00 801444.00 684320.00 117124.00 6/1/2014 6 June 2014
602 Government France Velo 1190 7.00 8330.00 1082.90 7247.10 5950.00 1297.10 6/1/2014 6 June 2014
603 Channel Partners Mexico Velo 604 12.00 7248.00 942.24 6305.76 1812.00 4493.76 6/1/2014 6 June 2014
604 Midmarket Germany Velo 660 15.00 9900.00 1287.00 8613.00 6600.00 2013.00 9/1/2013 9 September 2013
605 Channel Partners Mexico Velo 410 12.00 4920.00 639.60 4280.40 1230.00 3050.40 10/1/2014 10 October 2014
606 Small Business Mexico Velo 2605 300.00 781500.00 101595.00 679905.00 651250.00 28655.00 11/1/2013 11 November 2013
607 Channel Partners Germany Velo 1013 12.00 12156.00 1580.28 10575.72 3039.00 7536.72 12/1/2014 12 December 2014
608 Enterprise Canada VTT 1583 125.00 197875.00 25723.75 172151.25 189960.00 -17808.75 6/1/2014 6 June 2014
609 Midmarket Canada VTT 1565 15.00 23475.00 3051.75 20423.25 15650.00 4773.25 10/1/2014 10 October 2014
610 Enterprise Canada Amarilla 1659 125.00 207375.00 26958.75 180416.25 199080.00 -18663.75 1/1/2014 1 January 2014
611 Government France Amarilla 1190 7.00 8330.00 1082.90 7247.10 5950.00 1297.10 6/1/2014 6 June 2014
612 Channel Partners Mexico Amarilla 410 12.00 4920.00 639.60 4280.40 1230.00 3050.40 10/1/2014 10 October 2014
613 Channel Partners Germany Amarilla 1770 12.00 21240.00 2761.20 18478.80 5310.00 13168.80 12/1/2013 12 December 2013
614 Government Mexico Carretera 2579 20.00 51580.00 7221.20 44358.80 25790.00 18568.80 4/1/2014 4 April 2014
615 Government United States of America Carretera 1743 20.00 34860.00 4880.40 29979.60 17430.00 12549.60 5/1/2014 5 May 2014
616 Government United States of America Carretera 2996 7.00 20972.00 2936.08 18035.92 14980.00 3055.92 10/1/2013 10 October 2013
617 Government Germany Carretera 280 7.00 1960.00 274.40 1685.60 1400.00 285.60 12/1/2014 12 December 2014
618 Government France Montana 293 7.00 2051.00 287.14 1763.86 1465.00 298.86 2/1/2014 2 February 2014
619 Government United States of America Montana 2996 7.00 20972.00 2936.08 18035.92 14980.00 3055.92 10/1/2013 10 October 2013
620 Midmarket Germany Paseo 278 15.00 4170.00 583.80 3586.20 2780.00 806.20 2/1/2014 2 February 2014
621 Government Canada Paseo 2428 20.00 48560.00 6798.40 41761.60 24280.00 17481.60 3/1/2014 3 March 2014
622 Midmarket United States of America Paseo 1767 15.00 26505.00 3710.70 22794.30 17670.00 5124.30 9/1/2014 9 September 2014
623 Channel Partners France Paseo 1393 12.00 16716.00 2340.24 14375.76 4179.00 10196.76 10/1/2014 10 October 2014
624 Government Germany VTT 280 7.00 1960.00 274.40 1685.60 1400.00 285.60 12/1/2014 12 December 2014
625 Channel Partners France Amarilla 1393 12.00 16716.00 2340.24 14375.76 4179.00 10196.76 10/1/2014 10 October 2014
626 Channel Partners United States of America Amarilla 2015 12.00 24180.00 3385.20 20794.80 6045.00 14749.80 12/1/2013 12 December 2013
627 Small Business Mexico Carretera 801 300.00 240300.00 33642.00 206658.00 200250.00 6408.00 7/1/2014 7 July 2014
628 Enterprise France Carretera 1023 125.00 127875.00 17902.50 109972.50 122760.00 -12787.50 9/1/2013 9 September 2013
629 Small Business Canada Carretera 1496 300.00 448800.00 62832.00 385968.00 374000.00 11968.00 10/1/2014 10 October 2014
630 Small Business United States of America Carretera 1010 300.00 303000.00 42420.00 260580.00 252500.00 8080.00 10/1/2014 10 October 2014
631 Midmarket Germany Carretera 1513 15.00 22695.00 3177.30 19517.70 15130.00 4387.70 11/1/2014 11 November 2014
632 Midmarket Canada Carretera 2300 15.00 34500.00 4830.00 29670.00 23000.00 6670.00 12/1/2014 12 December 2014
633 Enterprise Mexico Carretera 2821 125.00 352625.00 49367.50 303257.50 338520.00 -35262.50 12/1/2013 12 December 2013
634 Government Canada Montana 2227.5 350.00 779625.00 109147.50 670477.50 579150.00 91327.50 1/1/2014 1 January 2014
635 Government Germany Montana 1199 350.00 419650.00 58751.00 360899.00 311740.00 49159.00 4/1/2014 4 April 2014
636 Government Canada Montana 200 350.00 70000.00 9800.00 60200.00 52000.00 8200.00 5/1/2014 5 May 2014
637 Government Canada Montana 388 7.00 2716.00 380.24 2335.76 1940.00 395.76 9/1/2014 9 September 2014
638 Government Mexico Montana 1727 7.00 12089.00 1692.46 10396.54 8635.00 1761.54 10/1/2013 10 October 2013
639 Midmarket Canada Montana 2300 15.00 34500.00 4830.00 29670.00 23000.00 6670.00 12/1/2014 12 December 2014
640 Government Mexico Paseo 260 20.00 5200.00 728.00 4472.00 2600.00 1872.00 2/1/2014 2 February 2014
641 Midmarket Canada Paseo 2470 15.00 37050.00 5187.00 31863.00 24700.00 7163.00 9/1/2013 9 September 2013
642 Midmarket Canada Paseo 1743 15.00 26145.00 3660.30 22484.70 17430.00 5054.70 10/1/2013 10 October 2013
643 Channel Partners United States of America Paseo 2914 12.00 34968.00 4895.52 30072.48 8742.00 21330.48 10/1/2014 10 October 2014
644 Government France Paseo 1731 7.00 12117.00 1696.38 10420.62 8655.00 1765.62 10/1/2014 10 October 2014
645 Government Canada Paseo 700 350.00 245000.00 34300.00 210700.00 182000.00 28700.00 11/1/2014 11 November 2014
646 Channel Partners Canada Paseo 2222 12.00 26664.00 3732.96 22931.04 6666.00 16265.04 11/1/2013 11 November 2013
647 Government United States of America Paseo 1177 350.00 411950.00 57673.00 354277.00 306020.00 48257.00 11/1/2014 11 November 2014
648 Government France Paseo 1922 350.00 672700.00 94178.00 578522.00 499720.00 78802.00 11/1/2013 11 November 2013
649 Enterprise Mexico Velo 1575 125.00 196875.00 27562.50 169312.50 189000.00 -19687.50 2/1/2014 2 February 2014
650 Government United States of America Velo 606 20.00 12120.00 1696.80 10423.20 6060.00 4363.20 4/1/2014 4 April 2014
651 Small Business United States of America Velo 2460 300.00 738000.00 103320.00 634680.00 615000.00 19680.00 7/1/2014 7 July 2014
652 Small Business Canada Velo 269 300.00 80700.00 11298.00 69402.00 67250.00 2152.00 10/1/2013 10 October 2013
653 Small Business Germany Velo 2536 300.00 760800.00 106512.00 654288.00 634000.00 20288.00 11/1/2013 11 November 2013
654 Government Mexico VTT 2903 7.00 20321.00 2844.94 17476.06 14515.00 2961.06 3/1/2014 3 March 2014
655 Small Business United States of America VTT 2541 300.00 762300.00 106722.00 655578.00 635250.00 20328.00 8/1/2014 8 August 2014
656 Small Business Canada VTT 269 300.00 80700.00 11298.00 69402.00 67250.00 2152.00 10/1/2013 10 October 2013
657 Small Business Canada VTT 1496 300.00 448800.00 62832.00 385968.00 374000.00 11968.00 10/1/2014 10 October 2014
658 Small Business United States of America VTT 1010 300.00 303000.00 42420.00 260580.00 252500.00 8080.00 10/1/2014 10 October 2014
659 Government France VTT 1281 350.00 448350.00 62769.00 385581.00 333060.00 52521.00 12/1/2013 12 December 2013
660 Small Business Canada Amarilla 888 300.00 266400.00 37296.00 229104.00 222000.00 7104.00 3/1/2014 3 March 2014
661 Enterprise United States of America Amarilla 2844 125.00 355500.00 49770.00 305730.00 341280.00 -35550.00 5/1/2014 5 May 2014
662 Channel Partners France Amarilla 2475 12.00 29700.00 4158.00 25542.00 7425.00 18117.00 8/1/2014 8 August 2014
663 Midmarket Canada Amarilla 1743 15.00 26145.00 3660.30 22484.70 17430.00 5054.70 10/1/2013 10 October 2013
664 Channel Partners United States of America Amarilla 2914 12.00 34968.00 4895.52 30072.48 8742.00 21330.48 10/1/2014 10 October 2014
665 Government France Amarilla 1731 7.00 12117.00 1696.38 10420.62 8655.00 1765.62 10/1/2014 10 October 2014
666 Government Mexico Amarilla 1727 7.00 12089.00 1692.46 10396.54 8635.00 1761.54 10/1/2013 10 October 2013
667 Midmarket Mexico Amarilla 1870 15.00 28050.00 3927.00 24123.00 18700.00 5423.00 11/1/2013 11 November 2013
668 Enterprise France Carretera 1174 125.00 146750.00 22012.50 124737.50 140880.00 -16142.50 8/1/2014 8 August 2014
669 Enterprise Germany Carretera 2767 125.00 345875.00 51881.25 293993.75 332040.00 -38046.25 8/1/2014 8 August 2014
670 Enterprise Germany Carretera 1085 125.00 135625.00 20343.75 115281.25 130200.00 -14918.75 10/1/2014 10 October 2014
671 Small Business Mexico Montana 546 300.00 163800.00 24570.00 139230.00 136500.00 2730.00 10/1/2014 10 October 2014
672 Government Germany Paseo 1158 20.00 23160.00 3474.00 19686.00 11580.00 8106.00 3/1/2014 3 March 2014
673 Midmarket Canada Paseo 1614 15.00 24210.00 3631.50 20578.50 16140.00 4438.50 4/1/2014 4 April 2014
674 Government Mexico Paseo 2535 7.00 17745.00 2661.75 15083.25 12675.00 2408.25 4/1/2014 4 April 2014
675 Government Mexico Paseo 2851 350.00 997850.00 149677.50 848172.50 741260.00 106912.50 5/1/2014 5 May 2014
676 Midmarket Canada Paseo 2559 15.00 38385.00 5757.75 32627.25 25590.00 7037.25 8/1/2014 8 August 2014
677 Government United States of America Paseo 267 20.00 5340.00 801.00 4539.00 2670.00 1869.00 10/1/2013 10 October 2013
678 Enterprise Germany Paseo 1085 125.00 135625.00 20343.75 115281.25 130200.00 -14918.75 10/1/2014 10 October 2014
679 Midmarket Germany Paseo 1175 15.00 17625.00 2643.75 14981.25 11750.00 3231.25 10/1/2014 10 October 2014
680 Government United States of America Paseo 2007 350.00 702450.00 105367.50 597082.50 521820.00 75262.50 11/1/2013 11 November 2013
681 Government Mexico Paseo 2151 350.00 752850.00 112927.50 639922.50 559260.00 80662.50 11/1/2013 11 November 2013
682 Channel Partners United States of America Paseo 914 12.00 10968.00 1645.20 9322.80 2742.00 6580.80 12/1/2014 12 December 2014
683 Government France Paseo 293 20.00 5860.00 879.00 4981.00 2930.00 2051.00 12/1/2014 12 December 2014
684 Channel Partners Mexico Velo 500 12.00 6000.00 900.00 5100.00 1500.00 3600.00 3/1/2014 3 March 2014
685 Midmarket France Velo 2826 15.00 42390.00 6358.50 36031.50 28260.00 7771.50 5/1/2014 5 May 2014
686 Enterprise France Velo 663 125.00 82875.00 12431.25 70443.75 79560.00 -9116.25 9/1/2014 9 September 2014
687 Small Business United States of America Velo 2574 300.00 772200.00 115830.00 656370.00 643500.00 12870.00 11/1/2013 11 November 2013
688 Enterprise United States of America Velo 2438 125.00 304750.00 45712.50 259037.50 292560.00 -33522.50 12/1/2013 12 December 2013
689 Channel Partners United States of America Velo 914 12.00 10968.00 1645.20 9322.80 2742.00 6580.80 12/1/2014 12 December 2014
690 Government Canada VTT 865.5 20.00 17310.00 2596.50 14713.50 8655.00 6058.50 7/1/2014 7 July 2014
691 Midmarket Germany VTT 492 15.00 7380.00 1107.00 6273.00 4920.00 1353.00 7/1/2014 7 July 2014
692 Government United States of America VTT 267 20.00 5340.00 801.00 4539.00 2670.00 1869.00 10/1/2013 10 October 2013
693 Midmarket Germany VTT 1175 15.00 17625.00 2643.75 14981.25 11750.00 3231.25 10/1/2014 10 October 2014
694 Enterprise Canada VTT 2954 125.00 369250.00 55387.50 313862.50 354480.00 -40617.50 11/1/2013 11 November 2013
695 Enterprise Germany VTT 552 125.00 69000.00 10350.00 58650.00 66240.00 -7590.00 11/1/2014 11 November 2014
696 Government France VTT 293 20.00 5860.00 879.00 4981.00 2930.00 2051.00 12/1/2014 12 December 2014
697 Small Business France Amarilla 2475 300.00 742500.00 111375.00 631125.00 618750.00 12375.00 3/1/2014 3 March 2014
698 Small Business Mexico Amarilla 546 300.00 163800.00 24570.00 139230.00 136500.00 2730.00 10/1/2014 10 October 2014
699 Government Mexico Montana 1368 7.00 9576.00 1436.40 8139.60 6840.00 1299.60 2/1/2014 2 February 2014
700 Government Canada Paseo 723 7.00 5061.00 759.15 4301.85 3615.00 686.85 4/1/2014 4 April 2014
701 Channel Partners United States of America VTT 1806 12.00 21672.00 3250.80 18421.20 5418.00 13003.20 5/1/2014 5 May 2014
@@ -0,0 +1,62 @@
{
"openapi": "3.1.0",
"info": {
"title": "get weather data",
"description": "Retrieves current weather data for a location based on wttr.in.",
"version": "v1.0.0"
},
"servers": [
{
"url": "https://wttr.in"
}
],
"auth": [],
"paths": {
"/{location}": {
"get": {
"description": "Get weather information for a specific location",
"operationId": "GetCurrentWeather",
"parameters": [
{
"name": "location",
"in": "path",
"description": "City or location to retrieve the weather for",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "format",
"in": "query",
"description": "Always use j1 value for this parameter",
"required": true,
"schema": {
"type": "string",
"default": "j1"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Location not found"
}
},
"deprecated": false
}
}
},
"components": {
"schemes": {}
}
}