Appearance
Research Workflow Example
This page provides a complete example of how to use Octagon's specialized agents with the OpenAI Agents SDK to conduct a comprehensive investment research workflow.
Complete Public Market Research Workflow Example
The following example demonstrates how to set up a research workflow that:
- Gathers basic company information
- Analyzes SEC filings
- Analyzes earnings call transcripts
- Evaluates financial metrics
- Analyzes stock performance
- Generates a comprehensive investment report
Python
import asyncio
import os
from openai import AsyncOpenAI
from agents import Agent, OpenAIResponsesModel, Runner, ItemHelpers, MessageOutputItem, trace
# Set OpenAI API key for the coordinator agent
os.environ["OPENAI_API_KEY"] = "<your-openai-api-key>"
os.environ['OCTAGON_API_KEY'] = "<your-octagon-api-key>"
# Configure Octagon client
octagon_client = AsyncOpenAI(
api_key=os.environ['OCTAGON_API_KEY'],
base_url="https://api-gateway.octagonagents.com/v1",
)
# Create Octagon specialized private market agents
companies_agent = Agent(
name="Companies Database",
instructions="You retrieve private company information from Octagon's companies database.",
model=OpenAIResponsesModel(
model="octagon-companies-agent",
openai_client=octagon_client,
),
)
funding_agent = Agent(
name="Funding Analysis",
instructions="You analyze private company funding data, including funding rounds, investors, valuations, and investment trends.",
model=OpenAIResponsesModel(
model="octagon-funding-agent",
openai_client=octagon_client,
),
)
deals_agent = Agent(
name="M&A and IPO Analysis",
instructions="You analyze M&A and IPO transaction data, including acquisitions, mergers, and initial public offerings.",
model=OpenAIResponsesModel(
model="octagon-deals-agent",
openai_client=octagon_client,
),
)
investors_agent = Agent(
name="Investors Analysis",
instructions="You provide information about investors, their investment criteria, and past activities.",
model=OpenAIResponsesModel(
model="octagon-investors-agent",
openai_client=octagon_client,
),
)
debts_agent = Agent(
name="Private Debts Analysis",
instructions="You analyze private debts, borrowers, and lenders, providing insights on debt facilities and terms.",
model=OpenAIResponsesModel(
model="octagon-debts-agent",
openai_client=octagon_client,
),
)
deep_research_agent = Agent(
name="Deep Research",
instructions="You conduct in-depth research by aggregating information from multiple sources to provide comprehensive analysis and insights.",
model=OpenAIResponsesModel(
model="octagon-deep-research-agent",
openai_client=octagon_client,
),
)
# Create a research workflow coordinator with OpenAI
openai_client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])
coordinator = Agent(
name="Research Coordinator",
instructions=(
"You are a research coordinator tasked with gathering comprehensive information about a private company using specialized agent tools.\n"
"Follow this exact workflow:\n"
"1. Use `get_company_info` to retrieve basic company details.\n"
"2. Use `analyze_funding` to find funding round details and investors.\n"
"3. Use `analyze_deals` to check for M&A or IPO activities.\n"
"4. Use `analyze_investors` to learn more about the company's key investors.\n"
"5. Use `analyze_debts` to identify any debt facilities.\n"
"6. Finally, use `conduct_deep_research` to synthesize all gathered information and provide a comprehensive analysis or answer specific research questions requiring aggregation.\n\n"
"**CRITICAL INSTRUCTION:** For each step, you MUST formulate a clear, full-sentence question to ask the tool. This question should explicitly mention the company's name and its URL (if provided)."
"DO NOT just pass the company name/URL string. You MUST ask a specific question.\n\n"
"Example Questions:\n"
"- For `get_company_info`: 'Can you provide the basic company information for Example Corp (example.com)?'\n"
"- For `analyze_funding`: 'What are the details of recent funding rounds for Example Corp (example.com)?'\n"
"- For `conduct_deep_research`: 'Provide a deep research analysis on the competitive landscape for Example Corp (example.com), using the information gathered so far.'\n\n"
"Before calling each tool, briefly explain which step you are on and what information you are seeking.\n"
"Always follow the numbered steps in order and do not skip any."
),
model=OpenAIResponsesModel(
model="o3-mini",
openai_client=openai_client,
),
tools=[
companies_agent.as_tool(
tool_name="get_company_info",
tool_description="Retrieves basic information (like founding date, employee count, description) about a private company.",
),
funding_agent.as_tool(
tool_name="analyze_funding",
tool_description="Analyzes funding rounds, investors, valuations, and investment trends for a private company.",
),
deals_agent.as_tool(
tool_name="analyze_deals",
tool_description="Analyzes M&A activities and IPO data related to a private company.",
),
investors_agent.as_tool(
tool_name="analyze_investors",
tool_description="Provides detailed information about a company's investors and their investment history/criteria.",
),
debts_agent.as_tool(
tool_name="analyze_debts",
tool_description="Analyzes private debt facilities, borrowers, and lenders related to a company.",
),
deep_research_agent.as_tool(
tool_name="conduct_deep_research",
tool_description="Conducts in-depth research, aggregates information from multiple sources, and provides comprehensive analysis.",
),
],
)
# Updated function to handle the research workflow using the tools approach
async def run_research_workflow(company_name, company_url=None):
"""Run the research workflow using the Runner to handle tool calls."""
print(f"\n🔍 Researching {company_name}...\n")
print("=" * 60)
# Create a simple input for our coordinator agent with the company URL if provided
if company_url:
user_input = f"Create a comprehensive investment research report for {company_name} ({company_url})."
else:
user_input = f"Create a comprehensive investment research report for {company_name}."
try:
# Run the entire orchestration in a single trace
with trace("Private Market Research Orchestrator"):
result = await Runner.run(coordinator, user_input)
# Print each step's output
for item in result.new_items:
if isinstance(item, MessageOutputItem):
text = ItemHelpers.text_message_output(item)
if text:
print(f"\n{text}")
print("\n" + "=" * 60)
print("\n✅ Research complete!")
return result.final_output
except Exception as e:
print(f"\n❌ Error during research: {str(e)}")
return f"Error: {str(e)}"
async def process_stream(stream, source_name):
"""Process a streaming response and return the full text."""
full_response = ""
print(f"\n--- {source_name} ---\n")
async for event in stream:
if event.type == "response.output_text.delta":
content = event.delta
full_response += content
print(content, end="", flush=True)
print("\n")
return full_response
async def main():
"""Run a simple demo of Octagon private market agents using the tools-based approach."""
# The company to research - we're using Octagon AI as requested
company_name = "OpenAI"
company_url = "openai.com" # Including URL for better results with private company lookup
print("\n🤖 Octagon Private Market Agents Demo")
print("This demo shows how easily Octagon's specialized private market agents can be used for investment research")
print(f"OpenAI API Key: {os.environ.get('OPENAI_API_KEY', 'not-set')[:6]}...")
print(f"Octagon API Key: {os.environ.get('OCTAGON_API_KEY', 'not-set')[:6]}...")
# Run the research workflow
final_report = await run_research_workflow(company_name, company_url)
print("\nFinal report:")
print(final_report)
if __name__ == "__main__":
asyncio.run(main())
JavaScript
import { OpenAI } from 'openai';
import { Agent, OpenAIResponsesModel, Runner, ItemHelpers, MessageOutputItem, trace } from 'agents';
import dotenv from 'dotenv';
import { promisify } from 'util';
// Load environment variables from .env file
dotenv.config();
// Set OpenAI API key for the coordinator agent
const openaiApiKey = process.env.OPENAI_API_KEY || "<your-openai-api-key>";
const octagonApiKey = process.env.OCTAGON_API_KEY || "<your-octagon-api-key>";
// Configure Octagon client
const octagonClient = new OpenAI({
apiKey: octagonApiKey,
baseURL: "https://api-gateway.octagonagents.com/v1",
});
// Configure OpenAI client for coordinator
const openaiClient = new OpenAI({
apiKey: openaiApiKey,
});
// Create Octagon specialized private market agents
const companiesAgent = new Agent({
name: "Companies Database",
instructions: "You retrieve private company information from Octagon's companies database.",
model: new OpenAIResponsesModel({
model: "octagon-companies-agent",
openaiClient: octagonClient,
}),
});
const fundingAgent = new Agent({
name: "Funding Analysis",
instructions: "You analyze private company funding data, including funding rounds, investors, valuations, and investment trends.",
model: new OpenAIResponsesModel({
model: "octagon-funding-agent",
openaiClient: octagonClient,
}),
});
const dealsAgent = new Agent({
name: "M&A and IPO Analysis",
instructions: "You analyze M&A and IPO transaction data, including acquisitions, mergers, and initial public offerings.",
model: new OpenAIResponsesModel({
model: "octagon-deals-agent",
openaiClient: octagonClient,
}),
});
const investorsAgent = new Agent({
name: "Investors Analysis",
instructions: "You provide information about investors, their investment criteria, and past activities.",
model: new OpenAIResponsesModel({
model: "octagon-investors-agent",
openaiClient: octagonClient,
}),
});
const debtsAgent = new Agent({
name: "Private Debts Analysis",
instructions: "You analyze private debts, borrowers, and lenders, providing insights on debt facilities and terms.",
model: new OpenAIResponsesModel({
model: "octagon-debts-agent",
openaiClient: octagonClient,
}),
});
const deepResearchAgent = new Agent({
name: "Deep Research",
instructions: "You conduct in-depth research by aggregating information from multiple sources to provide comprehensive analysis and insights.",
model: new OpenAIResponsesModel({
model: "octagon-deep-research-agent",
openaiClient: octagonClient,
}),
});
// Create a research workflow coordinator with OpenAI
const coordinator = new Agent({
name: "Research Coordinator",
instructions: (
"You are a research coordinator tasked with gathering comprehensive information about a private company using specialized agent tools.\n" +
"Follow this exact workflow:\n" +
"1. Use `get_company_info` to retrieve basic company details.\n" +
"2. Use `analyze_funding` to find funding round details and investors.\n" +
"3. Use `analyze_deals` to check for M&A or IPO activities.\n" +
"4. Use `analyze_investors` to learn more about the company's key investors.\n" +
"5. Use `analyze_debts` to identify any debt facilities.\n" +
"6. Finally, use `conduct_deep_research` to synthesize all gathered information and provide a comprehensive analysis or answer specific research questions requiring aggregation.\n\n" +
"**CRITICAL INSTRUCTION:** For each step, you MUST formulate a clear, full-sentence question to ask the tool. This question should explicitly mention the company's name and its URL (if provided)." +
"DO NOT just pass the company name/URL string. You MUST ask a specific question.\n\n" +
"Example Questions:\n" +
"- For `get_company_info`: 'Can you provide the basic company information for Example Corp (example.com)?'\n" +
"- For `analyze_funding`: 'What are the details of recent funding rounds for Example Corp (example.com)?'\n" +
"- For `conduct_deep_research`: 'Provide a deep research analysis on the competitive landscape for Example Corp (example.com), using the information gathered so far.'\n\n" +
"Before calling each tool, briefly explain which step you are on and what information you are seeking.\n" +
"Always follow the numbered steps in order and do not skip any."
),
model: new OpenAIResponsesModel({
model: "o3-mini",
openaiClient: openaiClient,
}),
tools: [
companiesAgent.asTool({
toolName: "get_company_info",
toolDescription: "Retrieves basic information (like founding date, employee count, description) about a private company.",
}),
fundingAgent.asTool({
toolName: "analyze_funding",
toolDescription: "Analyzes funding rounds, investors, valuations, and investment trends for a private company.",
}),
dealsAgent.asTool({
toolName: "analyze_deals",
toolDescription: "Analyzes M&A activities and IPO data related to a private company.",
}),
investorsAgent.asTool({
toolName: "analyze_investors",
toolDescription: "Provides detailed information about a company's investors and their investment history/criteria.",
}),
debtsAgent.asTool({
toolName: "analyze_debts",
toolDescription: "Analyzes private debt facilities, borrowers, and lenders related to a company.",
}),
deepResearchAgent.asTool({
toolName: "conduct_deep_research",
toolDescription: "Conducts in-depth research, aggregates information from multiple sources, and provides comprehensive analysis.",
}),
],
});
// Function to run the research workflow using the tools approach
async function runResearchWorkflow(companyName, companyUrl = null) {
console.log(`\n🔍 Researching ${companyName}...\n`);
console.log("=".repeat(60));
// Create a simple input for our coordinator agent with the company URL if provided
const userInput = companyUrl
? `Create a comprehensive investment research report for ${companyName} (${companyUrl}).`
: `Create a comprehensive investment research report for ${companyName}.`;
try {
// Run the entire orchestration in a single trace
const result = await trace("Private Market Research Orchestrator", async () => {
const runResult = await Runner.run(coordinator, userInput);
// Print each step's output
for (const item of runResult.newItems) {
if (item instanceof MessageOutputItem) {
const text = ItemHelpers.textMessageOutput(item);
if (text) {
console.log(`\n${text}`);
}
}
}
return runResult;
});
console.log("\n" + "=".repeat(60));
console.log("\n✅ Research complete!");
return result.finalOutput;
} catch (error) {
console.log(`\n❌ Error during research: ${error.message}`);
return `Error: ${error.message}`;
}
}
async function processStream(stream, sourceName) {
let fullResponse = "";
console.log(`\n--- ${sourceName} ---\n`);
for await (const event of stream) {
if (event.type === "response.output_text.delta") {
const content = event.delta;
fullResponse += content;
process.stdout.write(content);
}
}
console.log("\n");
return fullResponse;
}
async function main() {
// The company to research
const companyName = "OpenAI";
const companyUrl = "openai.com"; // Including URL for better results with private company lookup
console.log("\n🤖 Octagon Private Market Agents Demo");
console.log("This demo shows how easily Octagon's specialized private market agents can be used for investment research");
console.log(`OpenAI API Key: ${process.env.OPENAI_API_KEY?.substring(0, 6) || "not-set"}...`);
console.log(`Octagon API Key: ${process.env.OCTAGON_API_KEY?.substring(0, 6) || "not-set"}...`);
// Run the research workflow
const finalReport = await runResearchWorkflow(companyName, companyUrl);
console.log("\nFinal report:");
console.log(finalReport);
}
// Run the main function
main().catch(error => {
console.error("Error in main:", error);
process.exit(1);
});
How the Research Workflow Works
The example code demonstrates two approaches to creating a research workflow:
Using the Agents SDK Handoff Mechanism: The first part of the code sets up a coordinator agent with handoffs to specialized Octagon agents. This uses the official Agents SDK pattern for agent delegation.
Manual Implementation: The second part (the
run_research_workflow
function) shows a manual implementation of the research workflow, which provides more control over the process and demonstrates how each agent is called in sequence.
Key Components
Specialized Agents: Each Octagon agent is specialized for a specific type of financial analysis:
- Companies Database agent for basic company information
- SEC Filings agent for regulatory filing analysis
- Earnings Call agent for transcript analysis
- Financial Metrics agent for financial statement analysis
- Stock Performance agent for market data analysis
- Report Generation agent for creating comprehensive reports
Coordinator Agent: The OpenAI GPT-4o model serves as a coordinator that orchestrates the workflow and delegates to specialized agents.
Context Passing: Each agent's findings are passed as context to subsequent agents, ensuring a cohesive analysis flow.
Running the Example
To run this example:
- Save the code to a file (e.g.,
octagon_research_workflow.py
oroctagon_research_workflow.js
) - Install the required dependencies:
cURL
pip install openai openai-agents
cURL
npm install openai openai-agents dotenv
- Replace the API key placeholders with your actual keys
- Run the script:
cURL
python octagon_research_workflow.py
cURL
node octagon_research_workflow.js
Customizing the Workflow
You can customize this workflow for your specific research needs:
- Different Company: Change the
company_name
variable to research a different company - Additional Agents: Add more specialized Octagon agents to the workflow
- Custom Instructions: Modify the instructions for each agent to focus on specific aspects of financial analysis
- Alternative Coordinator: Use a different OpenAI model for coordination, such as GPT-4 Turbo or GPT-3.5 Turbo
- Different Output Format: Customize the report generation step to output in different formats (PDF, JSON, etc.)
Next Steps
- Explore the OpenAI Agents SDK documentation for more advanced features
- Check out the Octagon API documentation for detailed information about available agents and endpoints
- Learn about Authentication for production deployment best practices