fix: migrate invalid AgentTeam kwargs to output=/execution= (fixes #3654)

AgentTeam.__init__ accepts neither verbose= nor **kwargs, so passing
verbose= raised TypeError at construction. Verbosity is controlled via the
consolidated output= param (silent/minimal/verbose) and iteration limits via
execution=. Migrated all internal CLI, template generators, and examples off
the removed verbose=/max_iter=/session= kwargs, and added an AST lint guard
that scans examples + internal CLI for invalid AgentTeam kwargs to prevent
regression.

Co-authored-by: Dhivya-Bharathy <[email protected]>
This commit is contained in:
praisonai-triage-agent[bot]andDhivya-Bharathy committed 2026-08-04 10:16:49 +00:00
1 parent 631299846c
commit 92c2b6dd64
12 files changed
+128 -17

No files matched your search

@@ -86,7 +86,7 @@ def method_1_simple_loop():
agents=[loop_agent],
tasks=[loop_task],
process="workflow",
max_iter=10 # Maximum iterations to prevent infinite loops
execution="balanced" # max_iter=10 preset to prevent infinite loops
)
print(f"🚀 Starting loop processing of {csv_file}")
@@ -64,7 +64,7 @@ def main():
agents=[url_agent],
tasks=[url_task],
process="workflow",
max_iter=10 # Adjust based on how many URLs you have
execution="balanced" # max_iter=10 preset; adjust for more URLs
)
print(f"🚀 Processing URLs from {csv_file}")
@@ -141,7 +141,7 @@ class DynamicAgentSystem:
agents=agents,
tasks=tasks,
process=process,
verbose=inputs['depth'] == 'detailed'
output="verbose" if inputs['depth'] == 'detailed' else "silent"
)
result = praison_agents.start()
@@ -66,7 +66,7 @@ research_task1 = Task(
agents_session1 = AgentTeam(
agents=[research_agent],
tasks=[research_task1],
session=session1, output="verbose"
output="verbose"
)
# Execute first session
@@ -105,7 +105,7 @@ analysis_task = Task(
agents_session2 = AgentTeam(
agents=[analysis_agent],
tasks=[analysis_task],
session=session2, output="verbose"
output="verbose"
)
print("Starting analysis session with previous context...")
@@ -155,7 +155,7 @@ synthesis_task = Task(
agents_recovery = AgentTeam(
agents=[synthesis_agent],
tasks=[synthesis_task],
session=recovery_session, output="verbose"
output="verbose"
)
print("Starting recovery session with full context from previous sessions...")
@@ -205,7 +205,7 @@ review_task = Task(
agents_reviewer = AgentTeam(
agents=[review_agent],
tasks=[review_task],
session=reviewer_session, output="verbose"
output="verbose"
)
print("Starting peer review session by different user...")
@@ -23,5 +23,5 @@ agent = Agent(
)
# Run the agent
result = AgentTeam(agents=[agent], verbose=10).start()
result = AgentTeam(agents=[agent], output="verbose").start()
print(result)
@@ -0,0 +1,107 @@
"""
AST lint guard preventing AgentTeam API drift (invalid ``verbose=`` kwarg).
``AgentTeam.__init__`` does not accept ``verbose``; verbosity is controlled via
the consolidated ``output`` parameter (e.g. ``output="silent"`` /
``output="verbose"``). This test AST-parses example and internal-CLI source and
fails if any ``AgentTeam(...)`` call passes a keyword not present in the real
constructor signature, so broken copy-paste snippets can't be reintroduced.
The valid kwarg set is read from the ``AgentTeam.__init__`` source via AST
(not ``inspect.signature``) because ``AgentTeam`` subclasses ``typing.Protocol``,
which makes ``inspect`` report a generic ``(*args, **kwargs)`` signature.
"""
import ast
from pathlib import Path
# Repo root: .../src/praisonai-agents/tests/unit/agents/<this file>
_REPO_ROOT = Path(__file__).resolve().parents[5]
_AGENTS_SRC = (
_REPO_ROOT
/ "src"
/ "praisonai-agents"
/ "praisonaiagents"
/ "agents"
/ "agents.py"
)
# Directories whose ``AgentTeam(...)`` calls must use valid kwargs only.
_SCAN_DIRS = [
_REPO_ROOT / "examples",
_REPO_ROOT / "src" / "praisonai" / "praisonai",
_REPO_ROOT / "src" / "praisonai-code" / "praisonai_code",
]
def _valid_agentteam_kwargs():
"""Extract real ``AgentTeam.__init__`` parameter names by parsing source."""
tree = ast.parse(_AGENTS_SRC.read_text(encoding="utf-8"))
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef) and node.name == "AgentTeam":
for item in node.body:
if isinstance(item, ast.FunctionDef) and item.name == "__init__":
args = item.args
names = {a.arg for a in args.args}
names.update(a.arg for a in args.kwonlyargs)
has_var_keyword = args.kwarg is not None
names.discard("self")
return names, has_var_keyword
raise AssertionError("AgentTeam.__init__ not found in agents.py")
def _is_agentteam_call(node: ast.Call) -> bool:
func = node.func
if isinstance(func, ast.Name):
return func.id == "AgentTeam"
if isinstance(func, ast.Attribute):
return func.attr == "AgentTeam"
return False
def _iter_python_files():
for base in _SCAN_DIRS:
if not base.exists():
continue
for path in base.rglob("*.py"):
yield path
def _find_bad_kwargs(path: Path, valid_kwargs):
try:
tree = ast.parse(path.read_text(encoding="utf-8"))
except (SyntaxError, UnicodeDecodeError):
return []
bad = []
for node in ast.walk(tree):
if isinstance(node, ast.Call) and _is_agentteam_call(node):
for kw in node.keywords:
if kw.arg is None:
continue # **kwargs spread — can't statically validate
if kw.arg not in valid_kwargs:
bad.append((kw.arg, node.lineno))
return bad
def test_real_agentteam_init_has_no_verbose_or_var_keyword():
valid_kwargs, has_var_keyword = _valid_agentteam_kwargs()
assert "verbose" not in valid_kwargs
assert "output" in valid_kwargs
assert not has_var_keyword, (
"AgentTeam.__init__ gained **kwargs; the lint guard below would be "
"silently bypassed. Update this test if that change is intentional."
)
def test_no_invalid_agentteam_kwargs_in_examples_and_cli():
valid_kwargs, _ = _valid_agentteam_kwargs()
failures = []
for path in _iter_python_files():
for arg, lineno in _find_bad_kwargs(path, valid_kwargs):
rel = path.relative_to(_REPO_ROOT)
failures.append(f"{rel}:{lineno} — invalid AgentTeam kwarg '{arg}'")
assert not failures, (
"AgentTeam called with invalid kwargs (use output='silent'/'verbose' "
"instead of verbose=):\n" + "\n".join(sorted(failures))
)
@@ -219,7 +219,7 @@ class MultiAgentHandler:
instructions=config.get('instructions', ''),
tools=tools if tools else None,
llm=config.get('llm') or llm or os.environ.get('OPENAI_MODEL_NAME', 'gpt-4o-mini'),
verbose=self.verbose
output="verbose" if self.verbose else "silent"
)
agents.append(agent)
@@ -243,7 +243,7 @@ class MultiAgentHandler:
agents=agents,
tasks=tasks,
process=process,
verbose=self.verbose
output="verbose" if self.verbose else "silent"
)
result = praison_agents.start()
@@ -797,7 +797,7 @@ t_import = time.perf_counter()
agent = Agent(name="Helper", instructions="You are helpful", llm="{self.DEFAULT_MODEL}", output="minimal")
task = Task(name="respond", description="{prompt}", expected_output="response", agent=agent)
agents = AgentTeam(agents=[agent], tasks=[task], verbose=0)
agents = AgentTeam(agents=[agent], tasks=[task], output="silent")
t_init = time.perf_counter()
result = agents.start()
@@ -845,7 +845,7 @@ agent1 = Agent(name="Analyzer", instructions="Analyze the request", llm="{self.D
agent2 = Agent(name="Responder", instructions="Provide a response", llm="{self.DEFAULT_MODEL}", output="minimal")
task1 = Task(name="analyze", description="Analyze: {prompt}", expected_output="analysis", agent=agent1)
task2 = Task(name="respond", description="Respond based on analysis", expected_output="response", agent=agent2)
agents = AgentTeam(agents=[agent1, agent2], tasks=[task1, task2], verbose=0)
agents = AgentTeam(agents=[agent1, agent2], tasks=[task1, task2], output="silent")
t_init = time.perf_counter()
result = agents.start()
@@ -2312,13 +2312,13 @@ class PraisonAI:
agents=agents_list,
tasks=tasks_list,
process=process_type,
verbose=1 if verbose else 0
output="minimal" if verbose else "silent"
)
else:
praison = AgentTeam(
agents=agents_list,
process=process_type,
verbose=1 if verbose else 0
output="minimal" if verbose else "silent"
)
praison.launch(port=port, host=host)
@@ -637,11 +637,15 @@ class TemplatesHandler:
tasks.append(task)
# Run
_verbose_level = workflow_config.get("verbose", 1)
_output_mode = "silent" if not _verbose_level else (
"minimal" if _verbose_level == 1 else "verbose"
)
praison_agents = AgentTeam(
agents=agents,
tasks=tasks,
process=workflow_config.get("process", "sequential"),
verbose=workflow_config.get("verbose", 1)
output=_output_mode
)
praison_agents.start()
elif "steps" in workflow_config:
@@ -1210,7 +1210,7 @@ def handle_research_command(self, query: str, model: str = None, verbose: bool =
)
print("[cyan]Gathering information with tools...[/cyan]")
agents = AgentTeam(agents=[research_assistant], tasks=[gather_task], verbose=0)
agents = AgentTeam(agents=[research_assistant], tasks=[gather_task], output="silent")
tool_results = agents.start()
# Enhance query with tool results
@@ -567,7 +567,7 @@ if __name__ == "__main__":
agents = AgentTeam(
agents=[primary_agent, secondary_agent],
tasks=[primary_task, verification_task],
verbose=True,
output="verbose",
)
# Execute