Skip to content

Commit 68124d4

Browse files
committed
Fix tool function parameter handling in examples and documentation
- Updated all example agents to use correct FunctionTool pattern - Tool functions now properly receive params as Record<string, any> - Added explicit function declarations for all tools - Fixed examples: quickstart, default_agent, callbacks, fields_planner - Updated README.md with correct usage pattern - Standardized CHANGELOG.md formatting for consistency This fixes the issue where tool parameters were not being passed correctly, causing errors like "cannot read properties of undefined" when LLMs called tools with parameters.
1 parent 77a9687 commit 68124d4

6 files changed

Lines changed: 238 additions & 37 deletions

File tree

CHANGELOG.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
11
# Changelog
22

3+
## [current_version]
4+
* Fixed tool function parameter handling in all examples and documentation
5+
* Updated README.md with correct FunctionTool usage pattern showing explicit function declarations
6+
* Fixed examples (quickstart, default_agent, callbacks, fields_planner) to use correct tool function signatures with `params: Record<string, any>`
37

4-
## [current_version]
8+
## [v1.0.4]
9+
* Migrated to @google/genai: Ported the codebase to use the official @google/genai package for improved Google AI integration
10+
* Added runAgent functionality: New capability to run agents directly by executing files, making the package more versatile when installed
11+
* Improved Environment Configuration: Moved project constants to .env file for better configuration management
12+
* Fixed automatic function declarations generation
13+
* Improved logic for checking whether to use Google AI or Vertex AI
14+
* Added bash script for quick build and package linking during development
15+
* Fixed VERSION object shorthand syntax error
16+
* Fixed ES module import issue in CLI tests on Node.js 18.x
17+
* Fixed undefined errors in LlmRequest.ts for strict TypeScript compilation
18+
* Fixed TypeScript isolatedModules errors for CI
19+
* Comprehensive test suite fixes across multiple components (FunctionTool, LlmAgentFields, sessionService, cliTools, BaseAgent, connectionsClient, enterpriseWebSearchTool, AgentTool, applicationIntegrationToolset, googleLlm, cli, asyncToolCallbacks, basetool, cliCreate)
20+
* Added automated testing with GitHub Actions: Continuous integration now runs automatically
21+
* Configured CI to run only unit tests
22+
* Updated GitHub Actions to run tests only for Node.js version 20.x
23+
* Fixed slow startup time on CLI run command
24+
* Removed spammy console logs for cleaner output
25+
* Cleaned up README
26+
* Added example agent to README for better onboarding
527

628
## [1.0.3]
729
* Removed JSDoc-based function description extraction, since JSDoc is not available at runtime for functions in TypeScript (unlike Python).

README.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,28 +83,50 @@ Here's a simple weather agent to get you started:
8383
```typescript
8484
// agent.ts
8585
import { LlmAgent } from 'adk-typescript/agents';
86-
import { ToolContext } from 'adk-typescript/tools';
86+
import { ToolContext, FunctionTool } from 'adk-typescript/tools';
8787
import { runAgent } from 'adk-typescript';
8888

89-
// Define a tool function with explicit parameters
89+
// Define a tool function - receives params as an object
9090
async function getWeather(
91-
city: string,
91+
params: Record<string, any>,
9292
context: ToolContext
9393
): Promise<{ temperature: string; condition: string }> {
94+
const city = params.city; // Extract city from params
9495
// Your weather API logic here
9596
return {
9697
temperature: '72°F',
9798
condition: 'Sunny'
9899
};
99100
}
100101

102+
// Create a tool with explicit function declaration
103+
const getWeatherTool = new FunctionTool({
104+
name: 'getWeather',
105+
description: 'Get current weather for a city',
106+
fn: getWeather,
107+
functionDeclaration: {
108+
name: 'getWeather',
109+
description: 'Get current weather for a city',
110+
parameters: {
111+
type: 'object',
112+
properties: {
113+
city: {
114+
type: 'string',
115+
description: 'Name of the city'
116+
}
117+
},
118+
required: ['city']
119+
}
120+
}
121+
});
122+
101123
// Create your agent
102124
export const rootAgent = new LlmAgent({
103125
name: 'weather_agent',
104126
model: 'gemini-2.0-flash',
105127
description: 'A helpful weather assistant',
106128
instruction: 'You help users get weather information. Use the getWeather tool when asked about weather.',
107-
tools: [getWeather], // Pass functions directly!
129+
tools: [getWeatherTool],
108130
});
109131

110132
// Run programmatically (optional)

examples/callbacks/agent.ts

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { LlmAgent } from 'adk-typescript/agents';
2-
import { ToolContext } from 'adk-typescript/tools';
2+
import { ToolContext, FunctionTool, BaseTool } from 'adk-typescript/tools';
33
import { CallbackContext } from 'adk-typescript/agents';
44
import { LlmRequest, LlmResponse } from 'adk-typescript/models';
5-
import { BaseTool } from 'adk-typescript/tools';
65
import { Content, Part } from 'adk-typescript/models';
76
import { runAgent } from 'adk-typescript';
87

@@ -11,14 +10,15 @@ import { runAgent } from 'adk-typescript';
1110
/**
1211
* Roll a die and return the rolled result.
1312
*
14-
* @param sides The integer number of sides the die has
13+
* @param params Tool parameters containing sides
1514
* @param toolContext The tool context
1615
* @returns The result of rolling the die
1716
*/
1817
function rollDie(
19-
sides: number,
18+
params: Record<string, any>,
2019
toolContext: ToolContext
2120
): number {
21+
const sides = params.sides;
2222
const result = Math.floor(Math.random() * sides) + 1;
2323

2424
if (!toolContext.state.get('rolls')) {
@@ -34,14 +34,15 @@ function rollDie(
3434
/**
3535
* Check if a given list of numbers are prime.
3636
*
37-
* @param nums The list of numbers to check
37+
* @param params Tool parameters containing nums
3838
* @param toolContext The tool context
3939
* @returns A string indicating which numbers are prime
4040
*/
4141
async function checkPrime(
42-
nums: number[],
42+
params: Record<string, any>,
4343
toolContext: ToolContext
4444
): Promise<string> {
45+
const nums = params.nums;
4546
const primes = new Set<number>();
4647

4748
for (const number of nums) {
@@ -198,6 +199,48 @@ function afterToolCb3(
198199

199200
// --- Agent Definition ---
200201

202+
// Create tools with explicit function declarations
203+
const rollDieTool = new FunctionTool({
204+
name: 'rollDie',
205+
description: 'Roll a die and return the rolled result',
206+
fn: rollDie,
207+
functionDeclaration: {
208+
name: 'rollDie',
209+
description: 'Roll a die and return the rolled result',
210+
parameters: {
211+
type: 'object',
212+
properties: {
213+
sides: {
214+
type: 'number',
215+
description: 'The integer number of sides the die has'
216+
}
217+
},
218+
required: ['sides']
219+
}
220+
}
221+
});
222+
223+
const checkPrimeTool = new FunctionTool({
224+
name: 'checkPrime',
225+
description: 'Check if a given list of numbers are prime',
226+
fn: checkPrime,
227+
functionDeclaration: {
228+
name: 'checkPrime',
229+
description: 'Check if a given list of numbers are prime',
230+
parameters: {
231+
type: 'object',
232+
properties: {
233+
nums: {
234+
type: 'array',
235+
description: 'The list of numbers to check',
236+
items: { type: 'number' }
237+
}
238+
},
239+
required: ['nums']
240+
}
241+
}
242+
});
243+
201244
export const rootAgent = new LlmAgent({
202245
name: 'data_processing_agent',
203246
model: 'gemini-2.0-flash',
@@ -219,7 +262,7 @@ export const rootAgent = new LlmAgent({
219262
You should always perform the previous 3 steps when asking for a roll and checking prime numbers.
220263
You should not rely on the previous history on prime results.
221264
`,
222-
tools: [rollDie, checkPrime],
265+
tools: [rollDieTool, checkPrimeTool],
223266
safetySettings: [
224267
{
225268
category: 'HARM_CATEGORY_DANGEROUS_CONTENT',

examples/default_agent/agent.ts

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import { LlmAgent as Agent } from 'adk-typescript/agents';
22
import { LlmRegistry } from 'adk-typescript/models';
3-
import { ToolContext } from 'adk-typescript/tools';
3+
import { ToolContext, FunctionTool } from 'adk-typescript/tools';
44
import { runAgent } from 'adk-typescript';
55

66
// --- Tool Functions ---
77

88
/**
99
* Returns current weather information for a specified city
10-
* @param city Name of the city to get weather for
10+
* @param params Tool parameters object containing city
1111
* @param context Optional ToolContext
1212
* @returns Promise resolving to weather information or error
1313
*/
1414
async function getWeather(
15-
city: string,
15+
params: Record<string, any>,
1616
context: ToolContext
1717
): Promise<{ status: string; report?: string; error_message?: string }> {
18+
const city = params.city;
1819
console.log(`--- Tool: getWeather called for city: ${city} ---`);
1920
const cityNormalized = city.toLowerCase().trim();
2021
const mockWeatherDb: Record<string, { status: string; report: string }> = {
@@ -28,10 +29,12 @@ async function getWeather(
2829

2930
/**
3031
* Gets the current local time and timezone.
32+
* @param params Tool parameters object (no parameters needed)
3133
* @param context Optional ToolContext
3234
* @returns Promise resolving to time information
3335
*/
3436
async function getCurrentTime(
37+
params: Record<string, any>,
3538
context: ToolContext
3639
): Promise<{ currentTime: string; timezone: string; }> {
3740
console.log(`--- Tool: getCurrentTime called ---`);
@@ -44,19 +47,51 @@ async function getCurrentTime(
4447

4548
// --- Agent Definition ---
4649

47-
// Use LlmRegistry to get a model instance
48-
const agentLlm = LlmRegistry.newLlm("gemini-2.0-flash"); // Or another compatible model
50+
// Create tools with explicit function declarations
51+
const getWeatherTool = new FunctionTool({
52+
name: 'getWeather',
53+
description: 'Returns current weather information for a specified city',
54+
fn: getWeather,
55+
functionDeclaration: {
56+
name: 'getWeather',
57+
description: 'Returns current weather information for a specified city',
58+
parameters: {
59+
type: 'object',
60+
properties: {
61+
city: {
62+
type: 'string',
63+
description: 'Name of the city to get weather for'
64+
}
65+
},
66+
required: ['city']
67+
}
68+
}
69+
});
70+
71+
const getCurrentTimeTool = new FunctionTool({
72+
name: 'getCurrentTime',
73+
description: 'Gets the current local time and timezone',
74+
fn: getCurrentTime,
75+
functionDeclaration: {
76+
name: 'getCurrentTime',
77+
description: 'Gets the current local time and timezone',
78+
parameters: {
79+
type: 'object',
80+
properties: {},
81+
required: []
82+
}
83+
}
84+
});
4985

5086
// Export the root agent for ADK tools to find
51-
// Now we can pass functions directly to the tools array!
5287
export const rootAgent = new Agent({
5388
name: "default_agent", // Unique agent name
54-
model: agentLlm, // LLM instance
89+
model: "gemini-2.0-flash",
5590
description: "Provides current weather and time information for cities.",
5691
instruction: "You are a helpful assistant. Use the 'getWeather' tool for weather queries " +
5792
"and the 'getCurrentTime' tool for time queries. Provide clear answers based on tool results. " +
5893
"If asked for weather AND time, use both tools.",
59-
tools: [getWeather, getCurrentTime], // Functions can now be passed directly!
94+
tools: [getWeatherTool, getCurrentTimeTool],
6095
});
6196

6297
// Run agent directly when this file is executed

examples/fields_planner/agent.ts

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
1-
2-
31
import { LlmAgent as Agent } from 'adk-typescript/agents';
42
import { BuiltInPlanner } from 'adk-typescript/planners';
5-
import { ToolContext } from 'adk-typescript/tools';
3+
import { ToolContext, FunctionTool } from 'adk-typescript/tools';
64
import { runAgent } from 'adk-typescript';
75

86
// --- Tool Functions ---
97

108
/**
119
* Roll a die and return the rolled result.
1210
*
13-
* @param sides The integer number of sides the die has.
11+
* @param params Tool parameters containing sides
1412
* @param toolContext The tool context for state management.
1513
* @returns An integer of the result of rolling the die.
1614
*/
1715
function rollDie(
18-
sides: number,
16+
params: Record<string, any>,
1917
toolContext: ToolContext
2018
): number {
19+
const sides = params.sides;
2120
const result = Math.floor(Math.random() * sides) + 1;
2221

2322
if (!toolContext.state.get('rolls')) {
@@ -33,12 +32,15 @@ function rollDie(
3332
/**
3433
* Check if a given list of numbers are prime.
3534
*
36-
* @param nums The list of numbers to check.
35+
* @param params Tool parameters containing nums
36+
* @param toolContext The tool context (optional)
3737
* @returns A string indicating which number is prime.
3838
*/
3939
async function checkPrime(
40-
nums: number[]
40+
params: Record<string, any>,
41+
toolContext?: ToolContext
4142
): Promise<string> {
43+
const nums = params.nums;
4244
const primes = new Set<number>();
4345

4446
for (const number of nums) {
@@ -67,6 +69,48 @@ async function checkPrime(
6769

6870
// --- Agent Definition ---
6971

72+
// Create tools with explicit function declarations
73+
const rollDieTool = new FunctionTool({
74+
name: 'rollDie',
75+
description: 'Roll a die and return the rolled result',
76+
fn: rollDie,
77+
functionDeclaration: {
78+
name: 'rollDie',
79+
description: 'Roll a die and return the rolled result',
80+
parameters: {
81+
type: 'object',
82+
properties: {
83+
sides: {
84+
type: 'number',
85+
description: 'The integer number of sides the die has'
86+
}
87+
},
88+
required: ['sides']
89+
}
90+
}
91+
});
92+
93+
const checkPrimeTool = new FunctionTool({
94+
name: 'checkPrime',
95+
description: 'Check if a given list of numbers are prime',
96+
fn: checkPrime,
97+
functionDeclaration: {
98+
name: 'checkPrime',
99+
description: 'Check if a given list of numbers are prime',
100+
parameters: {
101+
type: 'object',
102+
properties: {
103+
nums: {
104+
type: 'array',
105+
description: 'The list of numbers to check',
106+
items: { type: 'number' }
107+
}
108+
},
109+
required: ['nums']
110+
}
111+
}
112+
});
113+
70114
export const rootAgent = new Agent({
71115
model: 'gemini-2.0-flash',
72116
name: 'data_processing_agent',
@@ -88,7 +132,7 @@ export const rootAgent = new Agent({
88132
You should always perform the previous 3 steps when asking for a roll and checking prime numbers.
89133
You should not rely on the previous history on prime results.
90134
`,
91-
tools: [rollDie, checkPrime],
135+
tools: [rollDieTool, checkPrimeTool],
92136
planner: new BuiltInPlanner({
93137
includeThoughts: true,
94138
}),

0 commit comments

Comments
 (0)