Skip to content

Instantly share code, notes, and snippets.

@pierrejoye
Created April 10, 2025 03:58
Show Gist options
  • Save pierrejoye/943a12c135e405bb4919e676b0ce9c43 to your computer and use it in GitHub Desktop.
Save pierrejoye/943a12c135e405bb4919e676b0ce9c43 to your computer and use it in GitHub Desktop.
OpenAi tool_calls example in typescript
import { OpenAI } from "openai";
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
// Define the types for our functions
interface CandidateProfile {
name: string;
currentRole?: string;
yearsExperience: number;
desiredRole: string;
education: string;
skills: string[];
industryPreference?: string;
workPreference?: "remote" | "hybrid" | "onsite";
salaryExpectation?: number;
}
interface JobMarketInfo {
role: string;
industry?: string;
region?: string;
currentYear?: number;
}
interface SkillsGapInfo {
currentSkills: string[];
desiredRole: string;
}
// Initialize OpenAI client
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
// First, update your tools to match function names
const tools: OpenAI.ChatCompletionTool[] = [
{
type: "function",
function: {
name: 'gather_candidate_profile',
description: 'Collect profile information about the candidate',
parameters: {
type: 'object',
properties: {
name: { type: 'string' },
currentRole: { type: 'string' },
yearsExperience: { type: 'number' },
desiredRole: { type: 'string' },
education: { type: 'string' },
skills: {
type: 'array',
items: { type: 'string' }
},
industryPreference: { type: 'string' },
workPreference: {
type: 'string',
enum: ['remote', 'hybrid', 'onsite']
},
salaryExpectation: { type: 'number' }
},
required: ['name', 'yearsExperience', 'desiredRole', 'education', 'skills']
}
}
},
{
type: 'function',
function: {
name: 'check_job_market',
description: 'Get current job market information for a specific role',
parameters: {
type: 'object',
properties: {
role: { type: 'string' },
industry: { type: 'string' },
region: { type: 'string' },
currentYear: { type: 'number' }
},
required: ['role']
}
}
},
{
type: 'function',
function: {
name: 'analyze_skills_gap',
description: 'Analyze the gap between current skills and those needed for a desired role',
parameters: {
type: 'object',
properties: {
currentSkills: {
type: 'array',
items: { type: 'string' }
},
desiredRole: { type: 'string' }
},
required: ['currentSkills', 'desiredRole']
}
}
}
];
const tool_choice: OpenAI.Chat.ChatCompletionToolChoiceOption = "auto";
// Mock function implementations that would normally connect to databases or APIs
async function gatherCandidateProfile(args: CandidateProfile): Promise<string> {
// In a real application, you might store this information in a database
console.log("Profile collected:", args);
return JSON.stringify({
status: "success",
message: "Candidate profile collected successfully",
profile: args
});
}
async function checkJobMarket(args: JobMarketInfo): Promise<string> {
// In a real application, this would fetch data from job market APIs or databases
const marketData = {
role: args.role,
industry: args.industry || "General",
demandLevel: args.role.includes("developer") ? "Very High" : "Moderate",
averageSalary: args.role.includes("developer") ? 120000 : 85000,
growthRate: args.role.includes("developer") ? "15% annually" : "8% annually",
topSkillsRequired: args.role.includes("developer")
? ["JavaScript", "TypeScript", "React", "Node.js"]
: ["Project Management", "Communication", "Leadership"],
remoteOpportunities: args.role.includes("developer") ? "Abundant" : "Limited"
};
return JSON.stringify(marketData);
}
async function analyzeSkillsGap(args: SkillsGapInfo): Promise<string> {
// In a real application, this would analyze skills against job requirements data
const skillsNeeded = getRequiredSkillsForRole(args.desiredRole);
const missingSkills = skillsNeeded.filter(skill => !args.currentSkills.includes(skill));
return JSON.stringify({
requiredSkills: skillsNeeded,
missingSkills: missingSkills,
recommendedCourses: missingSkills.map(skill => `${skill} Masterclass`),
estimatedTimeToAcquire: `${missingSkills.length * 2} months`
});
}
// Helper function to determine skills required for different roles
function getRequiredSkillsForRole(role: string): string[] {
const roleSkillsMap: Record<string, string[]> = {
"frontend developer": ["JavaScript", "HTML", "CSS", "React", "TypeScript", "UI/UX"],
"backend developer": ["Node.js", "Python", "Java", "SQL", "NoSQL", "API Design"],
"data scientist": ["Python", "R", "SQL", "Machine Learning", "Statistics", "Data Visualization"],
"product manager": ["Product Strategy", "User Research", "Roadmapping", "Agile", "Communication", "Analytics"],
"ux designer": ["User Research", "Wireframing", "Prototyping", "Figma", "UI Design", "User Testing"]
};
// Default to a generic set of skills if role isn't in our map
return roleSkillsMap[role.toLowerCase()] ||
["Communication", "Problem Solving", "Critical Thinking", "Collaboration", "Technical Aptitude"];
}
// Function to call the appropriate function based on name
async function callFunction(name: string, args: any): Promise<string> {
switch (name) {
case "gather_candidate_profile":
return await gatherCandidateProfile(args as CandidateProfile);
case "check_job_market":
return await checkJobMarket(args as JobMarketInfo);
case "analyze_skills_gap":
return await analyzeSkillsGap(args as SkillsGapInfo);
default:
return JSON.stringify({ error: "Function not found" });
}
}
// Main function to handle the career consultation process
async function careerConsultation(userInput: string) {
let finalResponse = null;
try {
const systemMessage: ChatCompletionMessageParam = {
role: "system",
content: `You are a career consultant.
Your job is to help users with their career-related questions and provide personalized advice.
Use the tools available to you to gather information and provide the best possible guidance.
If you need to ask the user for more information, do so in a friendly and professional manner.`
};
const userMessage: ChatCompletionMessageParam = {
role: "user",
content: userInput
};
const messages: ChatCompletionMessageParam[] = [
systemMessage,
userMessage
];
while (true) {
const completion = await openai.chat.completions.create({
model: "gpt-4o",
messages: messages,
tools: tools,
tool_choice: tool_choice,
});
const message = completion.choices[0]!.message;
console.log("Assistant response:", message.content);
messages.push(message);
if (!message.tool_calls || message.tool_calls.length === 0) {
console.log("No tool calls made by the assistant.");
// No tool calls, so we can return the assistant's message
finalResponse = message.content;
break;
}
console.log(`Model called ${message.tool_calls.length} tools`);
// Process each tool call
const toolCallPromises = message.tool_calls.map(async (toolCall) => {
if (toolCall.type === 'function') {
let functionArgs;
try {
functionArgs = JSON.parse(toolCall.function.arguments);
} catch (error) {
console.error("Error parsing arguments:", error);
return {
tool_call_id: toolCall.id,
role: "tool" as const,
content: JSON.stringify({ error: "Invalid arguments" })
};
}
const result = await callFunction(toolCall.function.name, functionArgs);
// Return the tool response in the expected format
return {
tool_call_id: toolCall.id,
role: "tool" as const,
content: result
};
}
return {
tool_call_id: toolCall.id,
role: "tool" as const,
content: JSON.stringify({ error: "Unsupported tool type" })
};
});
const toolResponses = await Promise.all(toolCallPromises);
messages.push(...toolResponses);
}
} catch (error) {
console.error("Error in career consultation:", error);
return "Sorry, there was an error processing your request.";
}
return finalResponse || "No response available.";
}
// Example usage
async function main() {
const userQuery = "I'm a marketing specialist with 4 years of experience, but I want to transition into UX design. I have a bachelor's in communications and I've done some design work on the side. What steps should I take?";
console.log("User:", userQuery);
const response = await careerConsultation(userQuery);
console.log("\nCareer Consultant:", response);
}
main().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment