Skip to content

Commit 65591aa

Browse files
feat: add CLI parity and YAML support for tool_search parameter
- Add 'praisonai agent run --tool-search=auto' CLI command - Add tool_search support to YAML agent configurations - Create comprehensive tool-search-example.yaml - Support all tool_search formats: false/true/auto/JSON - Follow progressive disclosure and AGENTS.md patterns - Maintain backward compatibility Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
1 parent 23ca2a8 commit 65591aa

4 files changed

Lines changed: 342 additions & 1 deletion

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Tool Search Example Configuration
2+
# This demonstrates using tool_search progressive disclosure for managing large tool sets
3+
4+
framework: praisonai
5+
topic: Research AI trends and write a comprehensive report
6+
7+
# Agents with tool search configuration
8+
agents:
9+
researcher:
10+
role: Research Analyst
11+
instructions: |
12+
You are a skilled research analyst with expertise in technology trends.
13+
Use available tools to research topics thoroughly.
14+
goal: Research topics thoroughly and provide insights
15+
tools:
16+
- internet_search
17+
- web_fetch
18+
- read_file
19+
- write_file
20+
# Tool search configuration - can be false/true/auto or object
21+
tool_search: auto
22+
23+
writer:
24+
role: Content Writer
25+
instructions: |
26+
You are a creative writer who can make complex topics engaging.
27+
You write in a clear, accessible style.
28+
goal: Create engaging content from research
29+
tools:
30+
- read_file
31+
- write_file
32+
- list_files
33+
# Advanced tool search configuration
34+
tool_search:
35+
enabled: "on"
36+
threshold_pct: 15
37+
search_default_limit: 10
38+
39+
analyst:
40+
role: Data Analyst
41+
instructions: |
42+
You analyze data and create visualizations.
43+
You work with structured data sources.
44+
goal: Analyze data trends
45+
tools:
46+
- read_csv
47+
- write_csv
48+
- analyze_csv
49+
# Tool search disabled
50+
tool_search: false
51+
52+
# Tasks
53+
tasks:
54+
research_task:
55+
description: Research current AI trends and emerging technologies
56+
expected_output: A comprehensive research report with latest AI trends
57+
agent: researcher
58+
59+
writing_task:
60+
description: Transform research into an engaging article
61+
expected_output: A well-written article about AI trends
62+
agent: writer
63+
64+
analysis_task:
65+
description: Analyze trends data if available
66+
expected_output: Data analysis summary
67+
agent: analyst
68+
69+
# Process configuration
70+
process: sequential
71+
verbose: true
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
"""
2+
Single Agent CLI Feature Handler
3+
4+
Provides CLI commands for running a single agent:
5+
- praisonai agent run --name "assistant" --task "Hello world" --tool-search auto
6+
7+
Example:
8+
praisonai agent run \
9+
--name "assistant" \
10+
--instructions "You are a helpful assistant" \
11+
--task "Help me with something" \
12+
--tool-search auto
13+
"""
14+
15+
import os
16+
from typing import Optional, List, Dict, Any, Union
17+
18+
19+
def parse_tool_search_param(value: str) -> Union[bool, str, Dict[str, Any]]:
20+
"""Parse tool_search parameter from CLI.
21+
22+
Args:
23+
value: String value from CLI parameter
24+
25+
Returns:
26+
Parsed value for tool_search parameter
27+
"""
28+
if value.lower() in ('false', 'off', 'disabled'):
29+
return False
30+
elif value.lower() in ('true', 'on', 'enabled'):
31+
return True
32+
elif value.lower() in ('auto',):
33+
return "auto"
34+
else:
35+
# Try to parse as JSON for advanced config
36+
try:
37+
import json
38+
return json.loads(value)
39+
except (json.JSONDecodeError, ValueError):
40+
# Treat as mode string
41+
return value
42+
43+
44+
class SingleAgentHandler:
45+
"""Handler for single agent CLI commands."""
46+
47+
def __init__(self, verbose: bool = True):
48+
"""Initialize the single agent handler.
49+
50+
Args:
51+
verbose: Whether to print verbose output
52+
"""
53+
self.verbose = verbose
54+
55+
def _load_tools(self, tool_names: List[str]) -> List:
56+
"""Load tool functions by name.
57+
58+
Args:
59+
tool_names: List of tool names to load
60+
61+
Returns:
62+
List of tool functions
63+
"""
64+
tools = []
65+
66+
try:
67+
from praisonaiagents.tools import (
68+
internet_search, read_file, write_file, list_files,
69+
execute_command, read_csv, write_csv, analyze_csv
70+
)
71+
72+
tool_map = {
73+
'internet_search': internet_search,
74+
'read_file': read_file,
75+
'write_file': write_file,
76+
'list_files': list_files,
77+
'execute_command': execute_command,
78+
'read_csv': read_csv,
79+
'write_csv': write_csv,
80+
'analyze_csv': analyze_csv,
81+
}
82+
83+
for name in tool_names:
84+
if name in tool_map:
85+
tools.append(tool_map[name])
86+
else:
87+
if self.verbose:
88+
print(f"⚠ Tool '{name}' not found, skipping")
89+
except ImportError as e:
90+
if self.verbose:
91+
print(f"⚠ Could not load tools: {e}")
92+
93+
return tools
94+
95+
def run(
96+
self,
97+
name: str = "assistant",
98+
instructions: Optional[str] = None,
99+
task: str = "Hello",
100+
llm: Optional[str] = None,
101+
tools: Optional[List[str]] = None,
102+
tool_search: Optional[str] = None,
103+
memory: bool = False,
104+
verbose: bool = False
105+
) -> str:
106+
"""Run a single agent with the given parameters.
107+
108+
Args:
109+
name: Agent name
110+
instructions: Agent instructions
111+
task: Task to execute
112+
llm: LLM model to use
113+
tools: List of tool names
114+
tool_search: Tool search configuration
115+
memory: Whether to enable memory
116+
verbose: Whether to enable verbose output
117+
118+
Returns:
119+
Agent execution result
120+
"""
121+
try:
122+
from praisonaiagents import Agent
123+
124+
# Parse tool_search parameter
125+
tool_search_config = None
126+
if tool_search:
127+
tool_search_config = parse_tool_search_param(tool_search)
128+
129+
# Load tools if specified
130+
agent_tools = None
131+
if tools:
132+
agent_tools = self._load_tools(tools)
133+
134+
# Create and run agent
135+
agent = Agent(
136+
name=name,
137+
instructions=instructions or f"You are a helpful agent named {name}.",
138+
llm=llm or os.environ.get('OPENAI_MODEL_NAME', 'gpt-4o-mini'),
139+
tools=agent_tools,
140+
tool_search=tool_search_config,
141+
memory=memory,
142+
verbose=verbose
143+
)
144+
145+
if self.verbose:
146+
print(f"\n🚀 Running agent '{name}'...")
147+
print(f"Task: {task}")
148+
if tool_search_config:
149+
print(f"Tool Search: {tool_search_config}")
150+
print()
151+
152+
result = agent.start(task)
153+
return str(result)
154+
155+
except Exception as e:
156+
if self.verbose:
157+
print(f"❌ Execution failed: {e}")
158+
raise
159+
160+
161+
def handle_agent_command(args) -> int:
162+
"""Handle agent subcommand from CLI.
163+
164+
Args:
165+
args: Parsed command line arguments
166+
167+
Returns:
168+
Exit code (0 for success, non-zero for error)
169+
"""
170+
handler = SingleAgentHandler(verbose=True)
171+
172+
try:
173+
if args.agent_command == "run":
174+
result = handler.run(
175+
name=getattr(args, 'name', 'assistant'),
176+
instructions=getattr(args, 'instructions', None),
177+
task=getattr(args, 'task', 'Hello'),
178+
llm=getattr(args, 'llm', None),
179+
tools=getattr(args, 'tools', None),
180+
tool_search=getattr(args, 'tool_search', None),
181+
memory=getattr(args, 'memory', False),
182+
verbose=getattr(args, 'verbose', False)
183+
)
184+
185+
print("\n" + "="*50)
186+
print("RESULT:")
187+
print("="*50)
188+
print(result)
189+
190+
else:
191+
print(f"Unknown agent command: {args.agent_command}")
192+
return 1
193+
194+
except Exception as e:
195+
print(f"Error: {e}")
196+
return 1
197+
198+
return 0
199+
200+
201+
def add_agent_parser(subparsers) -> None:
202+
"""Add agent subcommand to argument parser.
203+
204+
Args:
205+
subparsers: Subparsers object from argparse
206+
"""
207+
# run command
208+
run_parser = subparsers.add_parser(
209+
'run',
210+
help='Run a single agent with specified parameters'
211+
)
212+
run_parser.add_argument(
213+
'--name', '-n',
214+
default='assistant',
215+
help='Agent name (default: assistant)'
216+
)
217+
run_parser.add_argument(
218+
'--instructions', '-i',
219+
help='Agent instructions'
220+
)
221+
run_parser.add_argument(
222+
'--task', '-t',
223+
default='Hello',
224+
help='Task for the agent to complete (default: Hello)'
225+
)
226+
run_parser.add_argument(
227+
'--llm', '-m',
228+
help='LLM model to use'
229+
)
230+
run_parser.add_argument(
231+
'--tools',
232+
action='append',
233+
help='Tool names to load (can be used multiple times)'
234+
)
235+
run_parser.add_argument(
236+
'--tool-search',
237+
help='Tool search configuration (false/true/auto or JSON config)'
238+
)
239+
run_parser.add_argument(
240+
'--memory',
241+
action='store_true',
242+
help='Enable agent memory'
243+
)
244+
run_parser.add_argument(
245+
'--verbose', '-v',
246+
action='store_true',
247+
help='Enable verbose output'
248+
)

src/praisonai/praisonai/cli/main.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ def parse_args(self):
926926
return default_args
927927

928928
# Define special commands
929-
special_commands = ['chat', 'code', 'call', 'realtime', 'train', 'ui', 'context', 'research', 'memory', 'rules', 'workflow', 'hooks', 'knowledge', 'session', 'tools', 'todo', 'docs', 'mcp', 'commit', 'serve', 'schedule', 'skills', 'profile', 'eval', 'agents', 'run', 'thinking', 'compaction', 'output', 'deploy', 'templates', 'recipe', 'endpoints', 'audio', 'embed', 'embedding', 'images', 'moderate', 'files', 'batches', 'vector-stores', 'rerank', 'ocr', 'assistants', 'fine-tuning', 'completions', 'messages', 'guardrails', 'rag', 'videos', 'a2a', 'containers', 'passthrough', 'responses', 'search', 'realtime-api', 'doctor', 'registry', 'package', 'install', 'uninstall', 'acp', 'debug', 'lsp', 'diag', 'browser', 'replay', 'bot', 'gateway', 'sandbox', 'wizard', 'migrate', 'security', 'persistence', 'paths', 'claw', 'github', 'managed', 'flow', 'dashboard', 'backends']
929+
special_commands = ['chat', 'code', 'call', 'realtime', 'train', 'ui', 'context', 'research', 'memory', 'rules', 'workflow', 'hooks', 'knowledge', 'session', 'tools', 'todo', 'docs', 'mcp', 'commit', 'serve', 'schedule', 'skills', 'profile', 'eval', 'agent', 'agents', 'run', 'thinking', 'compaction', 'output', 'deploy', 'templates', 'recipe', 'endpoints', 'audio', 'embed', 'embedding', 'images', 'moderate', 'files', 'batches', 'vector-stores', 'rerank', 'ocr', 'assistants', 'fine-tuning', 'completions', 'messages', 'guardrails', 'rag', 'videos', 'a2a', 'containers', 'passthrough', 'responses', 'search', 'realtime-api', 'doctor', 'registry', 'package', 'install', 'uninstall', 'acp', 'debug', 'lsp', 'diag', 'browser', 'replay', 'bot', 'gateway', 'sandbox', 'wizard', 'migrate', 'security', 'persistence', 'paths', 'claw', 'github', 'managed', 'flow', 'dashboard', 'backends']
930930

931931
parser = argparse.ArgumentParser(prog="praisonai", description="praisonAI command-line interface")
932932
parser.add_argument("--framework", choices=["crewai", "autogen", "praisonai"], help="Specify the framework")
@@ -1589,6 +1589,24 @@ def parse_args(self):
15891589
exit_code = handle_serve_command(unknown_args)
15901590
sys.exit(exit_code)
15911591

1592+
elif args.command == 'agent':
1593+
# Agent command - run a single agent with tool search support
1594+
if not PRAISONAI_AVAILABLE:
1595+
print("[red]ERROR: PraisonAI Agents is not installed. Install with:[/red]")
1596+
print("\npip install praisonaiagents\n")
1597+
sys.exit(1)
1598+
1599+
from .features.agent import handle_agent_command, add_agent_parser
1600+
1601+
# Create a parser for agent command
1602+
agent_parser = argparse.ArgumentParser(prog="praisonai agent")
1603+
agent_subparsers = agent_parser.add_subparsers(dest='agent_command', help='Agent commands')
1604+
add_agent_parser(agent_subparsers)
1605+
agent_args = agent_parser.parse_args(unknown_args)
1606+
1607+
exit_code = handle_agent_command(agent_args)
1608+
sys.exit(exit_code)
1609+
15921610
elif args.command == 'agents':
15931611
# Agents command - run multiple agents with custom definitions
15941612
if not PRAISONAI_AVAILABLE:

src/praisonai/praisonai/framework_adapters/praisonai_adapter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ def run(
121121
agent_tools = details.get('tools', [])
122122
agent_tool_list = [tools_dict[t] for t in agent_tools if t in tools_dict]
123123

124+
# Parse tool_search configuration
125+
tool_search_config = details.get('tool_search', None)
126+
124127
# Create basic agent
125128
agent = PraisonAgent(
126129
name=role_filled,
@@ -131,6 +134,7 @@ def run(
131134
llm=model_name,
132135
allow_delegation=details.get('allow_delegation', False),
133136
tools=agent_tool_list,
137+
tool_search=tool_search_config,
134138
)
135139

136140
if agent_callback:

0 commit comments

Comments
 (0)