Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance agent tool function registration with direct function support #402

Merged
merged 1 commit into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/praisonai-ts/examples/simple/direct-function-tools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Agent } from 'praisonai';

/**
* Example of a simple agent with direct function registration
*
* This example demonstrates how to create a simple agent that uses directly
* registered functions as tools without having to define tool schemas manually
* or make functions globally available.
*/

// Define the functions directly
async function getWeather(location: string) {
console.log(`Getting weather for ${location}...`);
return `${Math.floor(Math.random() * 30)}°C`;
}

async function getTime(location: string) {
console.log(`Getting time for ${location}...`);
const now = new Date();
return `${now.getHours()}:${now.getMinutes()}`;
}

// Create an agent with directly registered functions
const agent = new Agent({
instructions: `You provide the current weather and time for requested locations.`,
name: "DirectFunctionAgent",
// Register functions directly without needing to make them global
toolFunctions: {
get_weather: getWeather,
get_time: getTime
}
});

// Start the agent with a prompt that will trigger tool usage
agent.start("What's the weather and time in Paris, France and Tokyo, Japan?");
73 changes: 73 additions & 0 deletions src/praisonai-ts/examples/simple/multi-tool-call.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Agent } from 'praisonai';

/**
* Example of a simple agent with multiple tool calling capability
*
* This example demonstrates how to create a simple agent that can use multiple tools
* to get weather and time information for different locations.
*/

// Define a weather tool
const getWeather = {
type: "function",
function: {
name: "get_weather",
description: "Get current temperature for a given location.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "City and country e.g. Bogotá, Colombia"
}
},
required: ["location"],
additionalProperties: false
},
strict: true
}
};

// Define a time tool
const getTime = {
type: "function",
function: {
name: "get_time",
description: "Get current time for a given location.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "City and country e.g. Bogotá, Colombia"
}
},
required: ["location"],
additionalProperties: false
},
strict: true
}
};

// Make the functions globally available
// The agent will automatically find and use these functions
(global as any).get_weather = async function(location: string) {
console.log(`Getting weather for ${location}...`);
return `${Math.floor(Math.random() * 30)}°C`;
};

(global as any).get_time = async function(location: string) {
console.log(`Getting time for ${location}...`);
const now = new Date();
return `${now.getHours()}:${now.getMinutes()}`;
};

// Create an agent with both weather and time tools
const agent = new Agent({
instructions: `You provide the current weather and time for requested locations.`,
name: "WeatherTimeAgent",
tools: [getWeather, getTime]
});

// Start the agent with a prompt that will trigger multiple tool calls
agent.start("What's the weather and time in Paris, France and Tokyo, Japan?");
46 changes: 46 additions & 0 deletions src/praisonai-ts/examples/simple/single-agent-tool-call.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Agent } from 'praisonai';

/**
* Example of a simple agent with tool calling capability
*
* This example demonstrates how to create a simple agent that can use tools
* to get weather information for a location.
*/

// Define a weather tool
const getWeather = {
type: "function",
function: {
name: "get_weather",
description: "Get current temperature for a given location.",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "City and country e.g. Bogotá, Colombia"
}
},
required: ["location"],
additionalProperties: false
},
strict: true
}
};

// Make the function globally available
// The agent will automatically find and use this function
(global as any).get_weather = async function(location: string) {
console.log(`Getting weather for ${location}...`);
return `20°C`;
};

// Create an agent with the weather tool
const agent = new Agent({
instructions: `You provide the current weather for requested locations.`,
name: "WeatherAgent",
tools: [getWeather]
});

// Start the agent with a prompt that will trigger tool usage
agent.start("What's the weather in Paris, France?");
4 changes: 2 additions & 2 deletions src/praisonai-ts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "praisonai",
"version": "1.0.17",
"version": "1.0.18",
"description": "PraisonAI TypeScript AI Agents Framework - Node.js, npm, and Javascript AI Agents Framework",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -62,7 +62,7 @@
"fast-xml-parser": "^4.5.1",
"node-fetch": "^2.6.9",
"openai": "^4.81.0",
"praisonai": "^1.0.12"
"praisonai": "^1.0.17"
},
"optionalDependencies": {
"boxen": "^7.1.1",
Expand Down
3 changes: 2 additions & 1 deletion src/praisonai-ts/src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export function setTaskMode(enabled: boolean) {
}

export { Agent, PraisonAIAgents, Task } from './proxy';
export type { ProxyAgentConfig } from './proxy';
export type { AgentConfig } from './types';
export type { TaskConfig } from './types';
export type { PraisonAIAgentsConfig } from './simple';
export type { PraisonAIAgentsConfig, SimpleAgentConfig } from './simple';
4 changes: 3 additions & 1 deletion src/praisonai-ts/src/agent/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ChatCompletionTool } from 'openai/resources/chat/completions';
export interface ProxyAgentConfig extends Partial<SimpleAgentConfig>, Partial<TaskAgentConfig> {
task?: Task;
tools?: any[];
toolFunctions?: Record<string, Function>;
}

export class Agent {
Expand Down Expand Up @@ -35,7 +36,8 @@ export class Agent {
verbose: config.verbose,
llm: config.llm,
markdown: config.markdown,
tools: config.tools
tools: config.tools,
toolFunctions: config.toolFunctions
};
this.simpleAgent = new SimpleAgent(simpleConfig);
}
Expand Down
83 changes: 83 additions & 0 deletions src/praisonai-ts/src/agent/simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface SimpleAgentConfig {
markdown?: boolean;
stream?: boolean;
tools?: any[];
toolFunctions?: Record<string, Function>;
}

export class Agent {
Expand Down Expand Up @@ -39,6 +40,18 @@ export class Agent {
// Configure logging
Logger.setVerbose(this.verbose);
Logger.setPretty(this.pretty);

// Register directly provided tool functions if any
if (config.toolFunctions) {
for (const [name, func] of Object.entries(config.toolFunctions)) {
this.registerToolFunction(name, func);

// Auto-generate tool definition if not already provided
if (!this.hasToolDefinition(name)) {
this.addAutoGeneratedToolDefinition(name, func);
}
}
}
}

private createSystemPrompt(): string {
Expand All @@ -58,6 +71,76 @@ export class Agent {
this.toolFunctions[name] = fn;
Logger.debug(`Registered tool function: ${name}`);
}

/**
* Check if a tool definition exists for the given function name
* @param name Function name
* @returns True if a tool definition exists
*/
private hasToolDefinition(name: string): boolean {
if (!this.tools) return false;

return this.tools.some(tool => {
if (tool.type === 'function' && tool.function) {
return tool.function.name === name;
}
return false;
});
}

/**
* Auto-generate a tool definition based on the function
* @param name Function name
* @param func Function implementation
*/
private addAutoGeneratedToolDefinition(name: string, func: Function): void {
if (!this.tools) {
this.tools = [];
}

// Extract parameter names from function
const funcStr = func.toString();
const paramMatch = funcStr.match(/\(([^)]*)\)/);
const params = paramMatch ? paramMatch[1].split(',').map(p => p.trim()).filter(p => p) : [];

// Create a basic tool definition
const toolDef = {
type: "function",
function: {
name,
description: `Auto-generated function for ${name}`,
parameters: {
type: "object",
properties: {},
required: [] as string[]
}
}
};

// Add parameters to the definition
if (params.length > 0) {
const properties: Record<string, any> = {};
const required: string[] = [];

params.forEach(param => {
// Remove type annotations if present
const paramName = param.split(':')[0].trim();
if (paramName) {
properties[paramName] = {
type: "string",
description: `Parameter ${paramName} for function ${name}`
};
required.push(paramName);
}
});

toolDef.function.parameters.properties = properties;
toolDef.function.parameters.required = required;
}

this.tools.push(toolDef);
Logger.debug(`Auto-generated tool definition for ${name}`);
}

/**
* Process tool calls from the model
Expand Down
35 changes: 35 additions & 0 deletions src/praisonai-ts/tests/development/simple/direct-function-tools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Agent } from '../../../src/agent/proxy';

/**
* Example of a simple agent with direct function registration
*
* This example demonstrates how to create a simple agent that uses directly
* registered functions as tools without having to define tool schemas manually
* or make functions globally available.
*/

// Define the functions directly
async function getWeather(location: string) {
console.log(`Getting weather for ${location}...`);
return `${Math.floor(Math.random() * 30)}°C`;
}

async function getTime(location: string) {
console.log(`Getting time for ${location}...`);
const now = new Date();
return `${now.getHours()}:${now.getMinutes()}`;
}

// Create an agent with directly registered functions
const agent = new Agent({
instructions: `You provide the current weather and time for requested locations.`,
name: "DirectFunctionAgent",
// Register functions directly without needing to make them global
toolFunctions: {
get_weather: getWeather,
get_time: getTime
}
});

// Start the agent with a prompt that will trigger tool usage
agent.start("What's the weather and time in Paris, France and Tokyo, Japan?");
Loading