What if after ending a gathering with a colleague you’ll have already got all of your mentioned objects in your project-management software? No want for writing something down through the assembly, nor to manually create corresponding tickets! That was the considered this quick experimental mission.
On this step-by-step information we are going to create the Python software “TaskPilot” utilizing OpenAI’s Brokers SDK to robotically create Jira points given a gathering transcript.
The Problem: From Dialog to Actionable Duties
Given the transcript of a gathering, create points in a Jira mission robotically and akin to what was mentioned within the assembly.
The Resolution: Automating with OpenAI Brokers
Utilizing the OpenAI Brokers SDK we are going to implement an brokers workflow that:
- Receives and reads a gathering transcript.
- Makes use of an AI agent to extract motion objects from the dialog.
- Makes use of one other AI agent to create Jira points from these motion objects.

The OpenAI Brokers SDK
The OpenAI Brokers SDK is a Python library to create AI brokers programmatically that may work together with instruments, use MCP-Servers or hand off duties to different brokers.
Listed here are a few of the key options of the SDK:
- Agent Loop: A built-in agent loop that handles the back-and-forth communication with the LLM till the agent is finished with its process.
- Perform Instruments: Turns any Python perform right into a software, with automated schema era and Pydantic-powered validation.
- MCP Assist: Permits brokers to make use of MCP servers to increase its capabilities of interacting with the surface world.
- Handoffs: Permits brokers to delegate duties to different brokers relying on their experience/position.
- Guardrails: Validates the inputs and outputs of the brokers. Aborts execution early if the agent receives invalid enter.
- Periods: Mechanically manages the dialog historical past. Ensures that the brokers have the context they should carry out their duties.
- Tracing: Gives a tracing context supervisor which permits to visualise your complete execution stream of the brokers, making it straightforward to debug and perceive what’s taking place below the hood.
Now, let’s dive into the implementation!
Implementation
We are going to implement our mission in 8 easy steps:
- Organising the mission construction
- The TaskPilotRunner
- Defining our knowledge fashions
- Creating the brokers
- Offering instruments
- Configuring the applying
- Bringing all of it collectively in
essential.py
- Monitoring our runs within the OpenAI Dev Platform
Let’s get fingers on!
Step 1: Setting Up the Venture Construction
First, let’s create the essential construction of our mission:
- The
taskpilot
listing: will include our essential software logic. - The
local_agents
listing: will include the place we outline the brokers we are going to use on this mission (“local_agents” in order that there isn’t a interference with the OpenAI librarybrokers
) - The
utils
listing: for helper features, a config parser and knowledge fashions.
taskpilot_repo/
├── config.yml
├── .env
├── README.md
├── taskpilot/
│ ├── essential.py
│ ├── taskpilot_runner.py
│ ├── local_agents/
│ │ ├── __init__.py
│ │ ├── action_items_extractor.py
│ │ └── tickets_creator.py
│ └── utils/
│ ├── __init__.py
│ ├── agents_tools.py
│ ├── config_parser.py
│ ├── jira_interface_functions.py
│ └── fashions.py
Step 2: The TaskPilotRunner
The TaskPilotRunner
class in taskpilot/taskpilot_runner.py
would be the coronary heart of our software. It would orchestrate your complete workflow, extracting motion objects from the assembly transcript after which creating the Jira tickets from the motion objects. On the identical time it should activate the built-in tracing from the Brokers SDK to gather a report of occasions through the brokers run that can assist for debugging and monitoring the agent workflows.
Let’s begin with the implementation:
- Within the
__init__()
methodology we are going to create the 2 brokers used for this workflow. - The
run()
methodology can be a very powerful of theTaskPilotRunner
class, which can obtain the assembly transcript and cross it to the brokers to create the Jira points. The brokers can be began and run inside a hint context supervisor i.e.with hint("TaskPilot run", trace_id):
. A hint from the Brokers SDK represents a single end-to-end operation of a “workflow”. - The
_extract_action_items()
and_create_tickets()
strategies will begin and run every of the brokers respectively. Inside these strategies theRunner.run()
methodology from the OpenAI Brokers SDK can be used to set off the brokers. It takes an agent and an enter, and it returns the ultimate output of the agent’s execution. Lastly, the results of every agent can be parsed to its outlined output sort.
# taskpilot/taskpilot_runner.py
from brokers import Runner, hint, gen_trace_id
from local_agents import create_action_items_agent, create_tickets_creator_agent
from utils.fashions import ActionItemsList, CreateIssuesResponse
class TaskPilotRunner:
def __init__(self):
self.action_items_extractor = create_action_items_agent()
self.tickets_creator = create_tickets_creator_agent()
async def run(self, meeting_transcript: str) -> None:
trace_id = gen_trace_id()
print(f"Beginning TaskPilot run... (Hint ID: {trace_id})")
print(
f"View hint: https://platform.openai.com/traces/hint?trace_id={trace_id}"
)
with hint("TaskPilot run", trace_id=trace_id):
# 1. Extract motion objects from assembly transcript
action_items = await self._extract_action_items(meeting_transcript)
# 2. Create tickets from motion objects
tickets_creation_response = await self._create_tickets(action_items)
# 3. Return the outcomes
print(tickets_creation_response.textual content)
async def _extract_action_items(self, meeting_transcript: str) -> ActionItemsList:
end result = await Runner.run(
self.action_items_extractor, enter=meeting_transcript
)
final_output = end result.final_output_as(ActionItemsList)
return final_output
async def _create_tickets(self, action_items: ActionItemsList) -> CreateIssuesResponse:
end result = await Runner.run(
self.tickets_creator, enter=str(action_items)
)
final_output = end result.final_output_as(CreateIssuesResponse)
return final_output
The three strategies are outlined as asynchronous features. The rationale for that is that the Runner.run()
methodology from the OpenAI Brokers SDK is outlined itself as an async
coroutine. This permits a number of brokers, software calls, or streaming endpoints to run in parallel with out blocking.
Step 3: Defining Our Knowledge Fashions
With out particular configuration brokers return textual content in str
as output. To make sure that our brokers present structured and predictable responses, the library helps the usage of Pydantic fashions for outlining the output_type
of the brokers (it truly helps any sort that may be wrapped in a Pydantic TypeAdapter — dataclasses, lists, TypedDict, and so on.). The info-models we outline would be the knowledge buildings that our brokers will work with.
For our usecase we are going to outline three fashions in taskpilot/utils/fashions.py
:
ActionItem
: This mannequin represents a single motion merchandise that’s extracted from the assembly transcript.ActionItemsList
: This mannequin is an inventory ofActionItem
objects.CreateIssuesResponse
: This mannequin defines the construction of the response from the agent that can create the problems/tickets.
# taskpilot/utils/fashions.py
from typing import Optionally available
from pydantic import BaseModel
class ActionItem(BaseModel):
title: str
description: str
assignee: str
standing: str
issuetype: str
mission: Optionally available[str] = None
due_date: Optionally available[str] = None
start_date: Optionally available[str] = None
precedence: Optionally available[str] = None
mother or father: Optionally available[str] = None
youngsters: Optionally available[list[str]] = None
class ActionItemsList(BaseModel):
action_items: listing[ActionItem]
class CreateIssuesResponse(BaseModel):
action_items: listing[ActionItem]
error_messages: listing[str]
success_messages: listing[str]
textual content: str
Step 4: Creating the Brokers
The brokers are the core of our software. Brokers are principally an LLM configured with directions (the AGENT_PROMPT
) and entry to instruments for them to behave by itself on outlined duties. An agent from the OpenAI Brokers SDK is outlined by the next parameters:
title
: The title of the agent for identification.directions
: The immediate to inform the agent its position or process it shall execute (aka. system immediate).mannequin
: Which LLM to make use of for the agent. The SDK supplies out-of-the-box help for OpenAI fashions, nevertheless you can even use non-OpenAI fashions (see Brokers SDK: Fashions).output_type
: Python object that the agent shall returned, as talked about beforehand.instruments
: An inventory of python callables, that would be the instruments that the agent can use to carry out its duties.
Primarily based on this info, let’s create our two brokers: the ActionItemsExtractor
and the TicketsCreator
.
Motion Objects Extractor
This agent’s job is to learn the assembly transcript and extract the motion objects. We’ll create it in taskpilot/local_agents/action_items_extractor.py
.
# taskpilot/local_agents/action_items_extractor.py
from brokers import Agent
from utils.config_parser import Config
from utils.fashions import ActionItemsList
AGENT_PROMPT = """
Your are an assistant to extract motion objects from a gathering transcript.
You can be given a gathering transcript and it's essential to extract the motion objects in order that they are often transformed into tickets by one other assistant.
The motion objects ought to include the next info:
- title: The title of the motion merchandise. It must be a brief description of the motion merchandise. It must be quick and concise. That is necessary.
- description: The outline of the motion merchandise. It must be a extra prolonged description of the motion merchandise. That is necessary.
- assignee: The title of the one who can be accountable for the motion merchandise. You shall infer from the dialog the title of the assignee and never use "Speaker 1" or "Speaker 2" or every other speaker identifier. That is necessary.
- standing: The standing of the motion merchandise. It may be "To Do", "In Progress", "In Evaluate" or "Completed". You shall extract from the transcript through which state the motion merchandise is. If it's a new motion merchandise, you shall set it to "To Do".
- due_date: The due date of the motion merchandise. It shall be within the format "YYYY-MM-DD". You shall extract this from the transcript, nevertheless if it isn't explicitly talked about, you shall set it to None. If relative dates are talked about (eg. by tomorrow, in every week,...), you shall convert them to absolute dates within the format "YYYY-MM-DD".
- start_date: The beginning date of the motion merchandise. It shall be within the format "YYYY-MM-DD". You shall extract this from the transcript, nevertheless if it isn't explicitly talked about, you shall set it to None.
- precedence: The precedence of the motion merchandise. It may be "Lowest", "Low", "Medium", "Excessive" or "Highest". You shall interpret the precedence of the motion merchandise from the transcript, nevertheless if it isn't clear, you shall set it to None.
- issuetype: The kind of the motion merchandise. It may be "Epic", "Bug", "Job", "Story", "Subtask". You shall interpret the issuetype of the motion merchandise from the transcript, whether it is unclear set it to "Job".
- mission: The mission to which the motion merchandise belongs. You shall interpret the mission of the motion merchandise from the transcript, nevertheless if it isn't clear, you shall set it to None.
- mother or father: If the motion merchandise is a subtask, you shall set the mother or father of the motion merchandise to the title of the mother or father motion merchandise. If the mother or father motion merchandise isn't clear or the motion merchandise isn't a subtask, you shall set it to None.
- youngsters: If the motion merchandise is a mother or father process, you shall set the kids of the motion merchandise to the titles of the kid motion objects. If the kids motion objects aren't clear or the motion merchandise isn't a mother or father process, you shall set it to None.
"""
def create_action_items_agent() -> Agent:
return Agent(
title="Motion Objects Extractor",
directions=AGENT_PROMPT,
output_type=ActionItemsList,
mannequin=Config.get().brokers.mannequin,
)
As you possibly can see, within the AGENT_PROMPT
we inform the agent very detailed that its job is to extract motion objects and supply an in depth description of how we wish the motion objects to be extracted.
Tickets Creator
This agent takes the listing of motion objects and creates Jira points. We’ll create it in taskpilot/local_agents/tickets_creator.py
.
# taskpilot/local_agents/tickets_creator.py
from brokers import Agent
from utils.config_parser import Config
from utils.agents_tools import create_jira_issue
from utils.fashions import CreateIssuesResponse
AGENT_PROMPT = """
You're an assistant that creates Jira points given motion objects.
You can be given an inventory of motion objects and for every motion merchandise you shall create a Jira situation utilizing the `create_jira_issue` software.
You shall gather the responses of the `create_jira_issue` software and return them because the offered sort `CreateIssuesResponse` which accommodates:
- action_items: listing containing the action_items that have been offered to you
- error_messages: listing containing the error messages returned by the `create_jira_issue` software at any time when there was an error making an attempt to create the problem.
- success_messages: listing containing the response messages returned by the `create_jira_issue` software at any time when the problem creation was profitable.
- textual content: A textual content that summarizes the results of the tickets creation. It shall be a string created as following:
f"From the {len(action_items)} motion objects offered {len(success_messages)} have been efficiently created within the Jira mission.n {len(error_messages)} did not be created within the Jira mission.nnError messages:n{error_messages}"
"""
def create_tickets_creator_agent() -> Agent:
return Agent(
title="Tickets Creator",
directions=AGENT_PROMPT,
instruments=[create_jira_issue],
mannequin=Config.get().brokers.mannequin,
output_type=CreateIssuesResponse
)
Right here we set the instruments
parameter and provides the agent the create_jira_issue
software, which we’ll create within the subsequent step.
Step 5: Offering Instruments
One of the vital highly effective options of brokers is their capacity to make use of instruments to work together with the surface world. One may argue that the usage of instruments is what turns the interplay with an LLM into an agent. The OpenAI Brokers SDK permits the brokers to make use of three kinds of instruments:
- Hosted instruments: Offered instantly from OpenAI corresponding to looking out the online or information, laptop use, working code, amongst others.
- Perform calling: Utilizing any Python perform as a software.
- Brokers as instruments: Permitting brokers to name different brokers with out handing off.
For our usecase, we can be utilizing perform calling and implement a perform to create the Jira points utilizing Jira’s REST API. By private selection, I made a decision to separate it in two information:
- In
taskpilot/utils/jira_interface_functions.py
we are going to write the features to work together by HTTP Requests with the Jira REST API. - In
taskpilot/utils/agents_tools.py
we are going to write wrappers of the features to be offered to the brokers. These wrapper-functions have extra response parsing to supply the agent a processed textual content response as an alternative of a JSON. However, the agent must also have the ability to deal with and perceive JSON as response.
First we implement the create_issue()
perform in taskpilot/utils/jira_interface_functions.py
:
# taskpilot/utils/jira_interface_functions.py
import os
from typing import Optionally available
import json
from urllib.parse import urljoin
import requests
from requests.auth import HTTPBasicAuth
from utils.config_parser import Config
JIRA_AUTH = HTTPBasicAuth(Config.get().jira.person, str(os.getenv("ATLASSIAN_API_KEY")))
def create_issue(
project_key: str,
title: str,
description: str,
issuetype: str,
duedate: Optionally available[str] = None,
assignee_id: Optionally available[str] = None,
labels: Optionally available[list[str]] = None,
priority_id: Optionally available[str] = None,
reporter_id: Optionally available[str] = None,
) -> requests.Response:
payload = {
"fields": {
"mission": {"key": project_key},
"abstract": title,
"issuetype": {"title": issuetype},
"description": {
"content material": [
{
"content": [
{
"text": description,
"type": "text",
}
],
"sort": "paragraph",
}
],
"sort": "doc",
"model": 1,
},
}
}
if duedate:
payload["fields"].replace({"duedate": duedate})
if assignee_id:
payload["fields"].replace({"assignee": {"id": assignee_id}})
if labels:
payload["fields"].replace({"labels": labels})
if priority_id:
payload["fields"].replace({"precedence": {"id": priority_id}})
if reporter_id:
payload["fields"].replace({"reporter": {"id": reporter_id}})
endpoint_url = urljoin(Config.get().jira.url_rest_api, "situation")
headers = {"Settle for": "software/json", "Content material-Kind": "software/json"}
response = requests.submit(
endpoint_url,
knowledge=json.dumps(payload),
headers=headers,
auth=JIRA_AUTH,
timeout=Config.get().jira.request_timeout,
)
return response
As you possibly can see, we have to authenticate to our Jira account utilizing our Jira person and a corresponding API_KEY
that we will receive on Atlassian Account Administration.
In taskpilot/utils/agents_tools.py
we implement the create_jira_issue()
perform, that we are going to then present to the TicketsCreator
agent:
# taskpilot/utils/agents_tools.py
from brokers import function_tool
from utils.fashions import ActionItem
from utils.jira_interface_functions import create_issue
@function_tool
def create_jira_issue(action_item: ActionItem) -> str:
response = create_issue(
project_key=action_item.mission,
title=action_item.title,
description=action_item.description,
issuetype=action_item.issuetype,
duedate=action_item.due_date,
assignee_id=None,
labels=None,
priority_id=None,
reporter_id=None,
)
if response.okay:
return f"Efficiently created the problem. Response message: {response.textual content}"
else:
return f"There was an error making an attempt to create the problem. Error message: {response.textual content}"
Essential: The @function_tool
decorator is what makes this perform usable for our agent. The agent can now name this perform and cross it an ActionItem
object. The perform then makes use of the create_issue
perform which accesses the Jira API to create a brand new situation.
Step 6: Configuring the Utility
To make our software parametrizable, we’ll use a config.yml
file for the configuration settings, in addition to a .env
file for the API keys.
The configuration of the applying is separated in:
brokers
: To configure the brokers and the entry to the OpenAI API. Right here we’ve two parameters:mannequin
, which is the LLM that shall be utilized by the brokers, andOPENAI_API_KEY
, within the.env
file, to authenticate the usage of the OpenAI API. You possibly can receive an OpenAI API Key in your OpenAI Dev Platform.jira
: To configure the entry to the Jira API. Right here we want 4 parameters:url_rest_api
, which is the URL to the REST API of our Jira occasion;person
, which is the person we use to entry Jira;request_timeout
, which is the timeout in seconds to attend for the server to ship knowledge earlier than giving up, and at lastATLASSIAN_API_KEY
, within the.env
file, to authenticate to your Jira occasion.
Right here is our .env
file, that within the subsequent step can be loaded to our software within the essential.py
utilizing the python-dotenv
library:
OPENAI_API_KEY=some-api-key
ATLASSIAN_API_KEY=some-api-key
And right here is our config.yml
file:
# config.yml
brokers:
mannequin: "o4-mini"
jira:
url_rest_api: "https://your-domain.atlassian.web/relaxation/api/3/"
person: "[email protected]"
request_timeout: 5
We’ll additionally create a config parser at taskpilot/utils/config_parser.py
to load this configuration. For this we implement the Config
class as a singleton (that means there can solely be one occasion of this class all through the applying lifespan).
# taskpilot/utils/config_parser.py
from pathlib import Path
import yaml
from pydantic import BaseModel
class AgentsConfig(BaseModel):
mannequin: str
class JiraConfig(BaseModel):
url_rest_api: str
person: str
request_timeout: int
class ConfigModel(BaseModel):
brokers: AgentsConfig
jira: JiraConfig
class Config:
_instance: ConfigModel | None = None
@classmethod
def load(cls, path: str = "config.yml") -> None:
if cls._instance is None:
with open(Path(path), "r", encoding="utf-8") as config_file:
raw_config = yaml.safe_load(config_file)
cls._instance = ConfigModel(**raw_config)
@classmethod
def get(cls, path: str = "config.yml") -> ConfigModel:
if cls._instance is None:
cls.load(path)
return cls._instance
Step 7: Bringing It All Collectively in essential.py
Lastly, in taskpilot/essential.py
, we’ll convey all the pieces collectively. This script will load the assembly transcript, create an occasion of the TaskPilotRunner
, after which name the run()
methodology.
# taskpilot/essential.py
import os
import asyncio
from dotenv import load_dotenv
from taskpilot_runner import TaskPilotRunner
# Load the variables within the .env file
load_dotenv()
def load_meeting_transcript_txt(file_path: str) -> str:
# ...
return meeting_transcript
async def essential():
print("TaskPilot software beginning...")
meeting_transcript = load_meeting_transcript_txt("meeting_transcript.txt")
await TaskPilotRunner().run(meeting_transcript)
if __name__ == "__main__":
asyncio.run(essential())
Step 8: Monitoring Our Runs within the OpenAI Dev Platform
As talked about, one of many benefits of the OpenAI Brokers SDK is that, as a result of its tracing characteristic, it’s potential to visualise your complete execution stream of our brokers. This makes it straightforward to debug and perceive what’s taking place below the hood within the OpenAI Dev Platform.
Within the Traces Dashboard one can:
- Monitor every run of the brokers workflow.

- Perceive precisely what the brokers did inside the agent workflow and monitor efficiency.

- Debug each name to the OpenAI API in addition to monitor what number of tokens have been utilized in every enter and output.

So reap the benefits of this characteristic to judge, debug and monitor your agent runs.
Conclusion
And that’s it! On this eight easy steps we’ve carried out an software that may robotically create Jira points from a gathering transcript. Because of the straightforward interface of the OpenAI Brokers SDK you possibly can simply create brokers programmatically that will help you automatize your duties!
Be happy to clone the repository (the mission as described on this submit is in department function_calling
), attempt it out for your self, and begin constructing your personal AI-powered purposes!
💡 Coming Up Subsequent:
In an upcoming submit, we’ll dive into tips on how to implement your personal MCP Server to additional lengthen our brokers’ capabilities and permit them to work together with exterior methods past your native instruments. Keep tuned!
🙋♂️ Let’s Join
When you’ve got questions, suggestions, or simply wish to comply with together with future initiatives:
Reference
This text is impressed by the “OpenAI: Brokers SDK” course from LinkedinLearning.