agentify-toolkit 0.19.0__tar.gz → 0.22.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/PKG-INFO +2 -1
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/pyproject.toml +2 -1
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/__init__.py +1 -1
- agentify_toolkit-0.22.0/src/agentify/_bin/_delete_cli.py +132 -0
- agentify_toolkit-0.22.0/src/agentify/cli/__init__.py +3 -0
- agentify_toolkit-0.22.0/src/agentify/cli/main.py +132 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/__init__.py +1 -2
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/agent.py +1 -1
- agentify_toolkit-0.22.0/src/agentify/commands/provider.py +106 -0
- agentify_toolkit-0.22.0/src/agentify/commands/run.py +85 -0
- agentify_toolkit-0.22.0/src/agentify/commands/runtime.py +227 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/serve.py +1 -1
- agentify_toolkit-0.22.0/src/agentify/commands/shell.py +7 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/tool.py +1 -1
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/gateway/server.py +12 -4
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/builtin_tools.py +1 -1
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/client.py +21 -8
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/registry.py +1 -1
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/server.py +3 -3
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/providers/__init__.py +2 -1
- agentify_toolkit-0.22.0/src/agentify/providers/agentify.py +47 -0
- agentify_toolkit-0.22.0/src/agentify/providers/anthropic.py +80 -0
- agentify_toolkit-0.22.0/src/agentify/providers/bedrock.py +107 -0
- agentify_toolkit-0.22.0/src/agentify/providers/deepseek.py +78 -0
- agentify_toolkit-0.22.0/src/agentify/providers/github.py +115 -0
- agentify_toolkit-0.22.0/src/agentify/providers/google.py +95 -0
- agentify_toolkit-0.22.0/src/agentify/providers/mistral.py +83 -0
- agentify_toolkit-0.22.0/src/agentify/providers/ollama.py +69 -0
- agentify_toolkit-0.22.0/src/agentify/providers/ollama_local.py +66 -0
- agentify_toolkit-0.22.0/src/agentify/providers/openai.py +70 -0
- agentify_toolkit-0.22.0/src/agentify/providers/rate_card.py +71 -0
- agentify_toolkit-0.22.0/src/agentify/providers/x.py +70 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/runtime/server.py +27 -7
- agentify_toolkit-0.22.0/src/agentify/sdk/__init__.py +0 -0
- agentify_toolkit-0.22.0/src/agentify/sdk/agent.py +564 -0
- agentify_toolkit-0.22.0/src/agentify/shell/app.py +461 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/utils/env_manager.py +4 -4
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/PKG-INFO +2 -1
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/SOURCES.txt +12 -13
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/requires.txt +1 -0
- agentify_toolkit-0.19.0/src/agentify/_cli.py +0 -662
- agentify_toolkit-0.19.0/src/agentify/_tool.py +0 -147
- agentify_toolkit-0.19.0/src/agentify/agent.py +0 -352
- agentify_toolkit-0.19.0/src/agentify/cli.py +0 -57
- agentify_toolkit-0.19.0/src/agentify/commands/_mcp.py +0 -183
- agentify_toolkit-0.19.0/src/agentify/commands/provider.py +0 -51
- agentify_toolkit-0.19.0/src/agentify/commands/run.py +0 -45
- agentify_toolkit-0.19.0/src/agentify/commands/runtime.py +0 -101
- agentify_toolkit-0.19.0/src/agentify/headers.py +0 -45
- agentify_toolkit-0.19.0/src/agentify/mcp_client.py +0 -23
- agentify_toolkit-0.19.0/src/agentify/mcpserver/__init__.py +0 -1
- agentify_toolkit-0.19.0/src/agentify/mcpserver/server.py +0 -237
- agentify_toolkit-0.19.0/src/agentify/providers/agentify.py +0 -42
- agentify_toolkit-0.19.0/src/agentify/providers/anthropic.py +0 -27
- agentify_toolkit-0.19.0/src/agentify/providers/bedrock.py +0 -30
- agentify_toolkit-0.19.0/src/agentify/providers/deepseek.py +0 -26
- agentify_toolkit-0.19.0/src/agentify/providers/github.py +0 -39
- agentify_toolkit-0.19.0/src/agentify/providers/google.py +0 -22
- agentify_toolkit-0.19.0/src/agentify/providers/mistral.py +0 -26
- agentify_toolkit-0.19.0/src/agentify/providers/ollama.py +0 -35
- agentify_toolkit-0.19.0/src/agentify/providers/ollama_local.py +0 -25
- agentify_toolkit-0.19.0/src/agentify/providers/openai.py +0 -22
- agentify_toolkit-0.19.0/src/agentify/providers/x.py +0 -23
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/LICENSE +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/NOTICE +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/README.md +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/setup.cfg +0 -0
- /agentify_toolkit-0.19.0/src/agentify/cli_ui.py → /agentify_toolkit-0.22.0/src/agentify/_bin/_delete_cli_ui.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/cli_config.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/config.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/deploy.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/gateway.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/mcp.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/__init__.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/providers/backplane.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/runtime/__init__.py +0 -0
- {agentify_toolkit-0.19.0/src/agentify → agentify_toolkit-0.22.0/src/agentify/runtime}/runtime_client.py +0 -0
- {agentify_toolkit-0.19.0/src/agentify → agentify_toolkit-0.22.0/src/agentify/sdk}/specs.py +0 -0
- {agentify_toolkit-0.19.0/src/agentify → agentify_toolkit-0.22.0/src/agentify/sdk}/tool.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/server/__init__.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/server/server.py +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/agent_list.css +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/agent_list.html +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/basic-chat.css +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/chat.css +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/chat.html +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/fun_agent_list.html +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/htmx.min.js +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/retro-chat.css +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/runtime_chat.html +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/dependency_links.txt +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/entry_points.txt +0 -0
- {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentify_toolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.0
|
|
4
4
|
Summary: Python Toolkit for Declarative AI Agent Development
|
|
5
5
|
Author-email: Lewis Sheridan <lewis@backplane.dev>
|
|
6
6
|
License: Apache License
|
|
@@ -115,6 +115,7 @@ Requires-Python: >=3.10
|
|
|
115
115
|
Description-Content-Type: text/markdown
|
|
116
116
|
License-File: LICENSE
|
|
117
117
|
License-File: NOTICE
|
|
118
|
+
Requires-Dist: tiktoken>=0.12.0
|
|
118
119
|
Requires-Dist: pyyaml>=6.0
|
|
119
120
|
Requires-Dist: rich>=13.0
|
|
120
121
|
Requires-Dist: click>=8.1
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentify_toolkit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.22.0"
|
|
8
8
|
description = "Python Toolkit for Declarative AI Agent Development"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -20,6 +20,7 @@ classifiers = [
|
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
dependencies = [
|
|
23
|
+
"tiktoken>=0.12.0",
|
|
23
24
|
"pyyaml>=6.0",
|
|
24
25
|
"rich>=13.0",
|
|
25
26
|
"click>=8.1",
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# src/agentify/cli.py
|
|
2
|
+
import click
|
|
3
|
+
import importlib
|
|
4
|
+
from agentify import __version__
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
|
|
8
|
+
# --- Console & Banner (instant) ---
|
|
9
|
+
console = Console(force_terminal=True)
|
|
10
|
+
agentify_icon = """
|
|
11
|
+
[white] ██ [/white]
|
|
12
|
+
[white] █████████████████[/white] Command: [yellow]agentify provider add <provider_name>[/yellow] [green]# e.g. openai, xai, anthropic[/green]
|
|
13
|
+
[white]░██ ░░███ ░░██[/white] Command: [yellow]agentify agent new[/yellow] [green]# <-- Creates a new Agent[/green]
|
|
14
|
+
[white]░██ ███ ██[/white] [green]# Run Agent[/green]
|
|
15
|
+
[white]░█████████████████[/white] Command: [yellow]agentify run agent.yaml[/yellow]
|
|
16
|
+
[white]░███████ ███████[/white] [green]# Start MCP Server[/green]
|
|
17
|
+
[white]░█████████████████[/white] Command: [yellow]agentify mcp start[/yellow]
|
|
18
|
+
[white]░░░██░░██░░██░░██ [/white] [green]# Start Agent Runtime → Deploy Agent[/green]
|
|
19
|
+
[white] ░██ ░██ ░██ ░██ [/white] Command: [yellow]agentify runtime start[/yellow] [green]→[/green] [yellow]agentify deploy agent.yaml[/yellow]
|
|
20
|
+
[white] ░░ ░░ ░░ ░░ [/white]
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
COMMANDS = {
|
|
24
|
+
"provider": {"target": "agentify.commands.provider:provider_group", "help": "Add, remove, or list AI providers (OpenAI, Anthropic, etc.)"},
|
|
25
|
+
"agent": {"target": "agentify.commands.agent:agent_group", "help": "Create, inspect, and manage AI agents"},
|
|
26
|
+
"run": {"target": "agentify.commands.run:run_command", "help": "Execute an agent from a YAML configuration file"},
|
|
27
|
+
"serve": {"target": "agentify.commands.serve:serve_command", "help": "Start an HTTP server to run an agent interactively"},
|
|
28
|
+
"deploy": {"target": "agentify.commands.deploy:deploy_command", "help": "Deploy an agent to a runtime or production environment"},
|
|
29
|
+
"runtime": {"target": "agentify.commands.runtime:runtime_group", "help": "Launch and manage the agent runtime environment"},
|
|
30
|
+
"gateway": {"target": "agentify.commands.gateway:gateway_command", "help": "Start the model gateway for routing AI requests"},
|
|
31
|
+
"tool": {"target": "agentify.commands.tool:tool_group", "help": "Add, remove, or manage tools for agent use"},
|
|
32
|
+
"mcp": {"target": "agentify.commands.mcp:mcp_group", "help": "Start and control the MCP server and associated services"},
|
|
33
|
+
"shell": {"target": "agentify.commands.shell:shell_command", "help": "Start Agentify Terminal Shell"},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# --- Lazy leaf command ---
|
|
37
|
+
class LazyCommand(click.Command):
|
|
38
|
+
def __init__(self, module_path: str, attr_name: str, help_text: str = None):
|
|
39
|
+
self.module_path = module_path
|
|
40
|
+
self.attr_name = attr_name
|
|
41
|
+
super().__init__(name=attr_name, help=help_text)
|
|
42
|
+
# Allow extra arguments (must be set after __init__)
|
|
43
|
+
self.allow_extra_args = True
|
|
44
|
+
self.ignore_unknown_options = True # Allows things like 'agent.yaml'
|
|
45
|
+
|
|
46
|
+
def invoke(self, ctx):
|
|
47
|
+
# Lazy import the actual command
|
|
48
|
+
module = importlib.import_module(self.module_path)
|
|
49
|
+
real_cmd = getattr(module, self.attr_name)
|
|
50
|
+
|
|
51
|
+
if not isinstance(real_cmd, click.Command):
|
|
52
|
+
raise click.ClickException(f"Command {self.attr_name} is not a Click Command")
|
|
53
|
+
|
|
54
|
+
# Forward raw CLI args to the real command
|
|
55
|
+
return real_cmd.main(args=ctx.args, standalone_mode=False)
|
|
56
|
+
|
|
57
|
+
# --- Lazy group command ---
|
|
58
|
+
class LazyGroupCommand(click.Group):
|
|
59
|
+
"""Lazy-loaded click.Group with subcommands."""
|
|
60
|
+
def __init__(self, module_path: str, attr_name: str, help_text: str = None):
|
|
61
|
+
self.module_path = module_path
|
|
62
|
+
self.attr_name = attr_name
|
|
63
|
+
super().__init__(name=attr_name, help=help_text)
|
|
64
|
+
|
|
65
|
+
def list_commands(self, ctx):
|
|
66
|
+
module = importlib.import_module(self.module_path)
|
|
67
|
+
real_group = getattr(module, self.attr_name)
|
|
68
|
+
return real_group.list_commands(ctx)
|
|
69
|
+
|
|
70
|
+
def get_command(self, ctx, name):
|
|
71
|
+
module = importlib.import_module(self.module_path)
|
|
72
|
+
real_group = getattr(module, self.attr_name)
|
|
73
|
+
return real_group.get_command(ctx, name)
|
|
74
|
+
|
|
75
|
+
# --- Lazy main group ---
|
|
76
|
+
class LazyMainGroup(click.Group):
|
|
77
|
+
def list_commands(self, ctx):
|
|
78
|
+
return COMMANDS.keys()
|
|
79
|
+
|
|
80
|
+
def get_command(self, ctx, name):
|
|
81
|
+
if name not in COMMANDS:
|
|
82
|
+
return None
|
|
83
|
+
module_path, attr_name = COMMANDS[name]["target"].split(":")
|
|
84
|
+
help_text = COMMANDS[name].get("help", None)
|
|
85
|
+
|
|
86
|
+
# If the attribute name ends with "_group", treat as LazyGroupCommand
|
|
87
|
+
if attr_name.endswith("_group"):
|
|
88
|
+
return LazyGroupCommand(module_path, attr_name, help_text)
|
|
89
|
+
else:
|
|
90
|
+
return LazyCommand(module_path, attr_name, help_text)
|
|
91
|
+
|
|
92
|
+
class LazyGroup(click.Group):
|
|
93
|
+
def list_commands(self, ctx):
|
|
94
|
+
return sorted(COMMANDS.keys())
|
|
95
|
+
|
|
96
|
+
def get_command(self, ctx, name):
|
|
97
|
+
if name not in COMMANDS:
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
# Split module path and attribute
|
|
101
|
+
module_path, attr_name = COMMANDS[name]["target"].split(":")
|
|
102
|
+
help_text = COMMANDS[name].get("help")
|
|
103
|
+
|
|
104
|
+
# Import module lazily
|
|
105
|
+
module = importlib.import_module(module_path)
|
|
106
|
+
cmd = getattr(module, attr_name)
|
|
107
|
+
|
|
108
|
+
# Attach help if missing
|
|
109
|
+
if help_text and getattr(cmd, "help", None) is None:
|
|
110
|
+
cmd.help = help_text
|
|
111
|
+
|
|
112
|
+
return cmd
|
|
113
|
+
|
|
114
|
+
# --- Main entrypoint ---
|
|
115
|
+
@click.group(cls=LazyMainGroup, invoke_without_command=True)
|
|
116
|
+
@click.version_option(version=__version__, prog_name="Agentify")
|
|
117
|
+
@click.pass_context
|
|
118
|
+
def main(ctx):
|
|
119
|
+
"""Agentify Toolkit CLI"""
|
|
120
|
+
# Show banner only if no subcommand is invoked
|
|
121
|
+
if ctx.invoked_subcommand is None:
|
|
122
|
+
console.print(
|
|
123
|
+
Panel(
|
|
124
|
+
agentify_icon,
|
|
125
|
+
title=f"AGENTIFY TOOLKIT CLI v{__version__}",
|
|
126
|
+
subtitle="Build, Run and deploy AI Agents declaratively",
|
|
127
|
+
border_style="white",
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
click.echo() # blank line
|
|
132
|
+
click.echo(ctx.command.get_help(ctx))
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# src/agentify/cli.py
|
|
2
|
+
import click
|
|
3
|
+
import importlib
|
|
4
|
+
from agentify import __version__
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.panel import Panel
|
|
7
|
+
|
|
8
|
+
# --- Console & Banner (instant) ---
|
|
9
|
+
console = Console(force_terminal=True)
|
|
10
|
+
agentify_icon = """
|
|
11
|
+
[white] ██ [/white]
|
|
12
|
+
[white] █████████████████[/white] Command: [yellow]agentify provider add <provider_name>[/yellow] [green]# e.g. openai, xai, anthropic[/green]
|
|
13
|
+
[white]░██ ░░███ ░░██[/white] Command: [yellow]agentify agent new[/yellow] [green]# <-- Creates a new Agent[/green]
|
|
14
|
+
[white]░██ ███ ██[/white] [green]# Run Agent[/green]
|
|
15
|
+
[white]░█████████████████[/white] Command: [yellow]agentify run agent.yaml[/yellow]
|
|
16
|
+
[white]░███████ ███████[/white] [green]# Start MCP Server[/green]
|
|
17
|
+
[white]░█████████████████[/white] Command: [yellow]agentify mcp start[/yellow]
|
|
18
|
+
[white]░░░██░░██░░██░░██ [/white] [green]# Start Agent Runtime → Deploy Agent[/green]
|
|
19
|
+
[white] ░██ ░██ ░██ ░██ [/white] Command: [yellow]agentify runtime start[/yellow] [green]→[/green] [yellow]agentify deploy agent.yaml[/yellow]
|
|
20
|
+
[white] ░░ ░░ ░░ ░░ [/white]
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
COMMANDS = {
|
|
24
|
+
"provider": {"target": "agentify.commands.provider:provider_group", "help": "Add, remove, or list AI providers (OpenAI, Anthropic, etc.)"},
|
|
25
|
+
"agent": {"target": "agentify.commands.agent:agent_group", "help": "Create, inspect, and manage AI agents"},
|
|
26
|
+
"run": {"target": "agentify.commands.run:run_command", "help": "Execute an agent from a YAML configuration file"},
|
|
27
|
+
"serve": {"target": "agentify.commands.serve:serve_command", "help": "Start an HTTP server to run an agent interactively"},
|
|
28
|
+
"deploy": {"target": "agentify.commands.deploy:deploy_command", "help": "Deploy an agent to a runtime or production environment"},
|
|
29
|
+
"runtime": {"target": "agentify.commands.runtime:runtime_group", "help": "Launch and manage the agent runtime environment"},
|
|
30
|
+
"gateway": {"target": "agentify.commands.gateway:gateway_command", "help": "Start the model gateway for routing AI requests"},
|
|
31
|
+
"tool": {"target": "agentify.commands.tool:tool_group", "help": "Add, remove, or manage tools for agent use"},
|
|
32
|
+
"mcp": {"target": "agentify.commands.mcp:mcp_group", "help": "Start and control the MCP server and associated services"},
|
|
33
|
+
"shell": {"target": "agentify.commands.shell:shell_command", "help": "Start Agentify Terminal Shell"},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# --- Lazy leaf command ---
|
|
37
|
+
class LazyCommand(click.Command):
|
|
38
|
+
def __init__(self, module_path: str, attr_name: str, help_text: str = None):
|
|
39
|
+
self.module_path = module_path
|
|
40
|
+
self.attr_name = attr_name
|
|
41
|
+
super().__init__(name=attr_name, help=help_text)
|
|
42
|
+
# Allow extra arguments (must be set after __init__)
|
|
43
|
+
self.allow_extra_args = True
|
|
44
|
+
self.ignore_unknown_options = True # Allows things like 'agent.yaml'
|
|
45
|
+
|
|
46
|
+
def invoke(self, ctx):
|
|
47
|
+
# Lazy import the actual command
|
|
48
|
+
module = importlib.import_module(self.module_path)
|
|
49
|
+
real_cmd = getattr(module, self.attr_name)
|
|
50
|
+
|
|
51
|
+
if not isinstance(real_cmd, click.Command):
|
|
52
|
+
raise click.ClickException(f"Command {self.attr_name} is not a Click Command")
|
|
53
|
+
|
|
54
|
+
# Forward raw CLI args to the real command
|
|
55
|
+
return real_cmd.main(args=ctx.args, standalone_mode=False)
|
|
56
|
+
|
|
57
|
+
# --- Lazy group command ---
|
|
58
|
+
class LazyGroupCommand(click.Group):
|
|
59
|
+
"""Lazy-loaded click.Group with subcommands."""
|
|
60
|
+
def __init__(self, module_path: str, attr_name: str, help_text: str = None):
|
|
61
|
+
self.module_path = module_path
|
|
62
|
+
self.attr_name = attr_name
|
|
63
|
+
super().__init__(name=attr_name, help=help_text)
|
|
64
|
+
|
|
65
|
+
def list_commands(self, ctx):
|
|
66
|
+
module = importlib.import_module(self.module_path)
|
|
67
|
+
real_group = getattr(module, self.attr_name)
|
|
68
|
+
return real_group.list_commands(ctx)
|
|
69
|
+
|
|
70
|
+
def get_command(self, ctx, name):
|
|
71
|
+
module = importlib.import_module(self.module_path)
|
|
72
|
+
real_group = getattr(module, self.attr_name)
|
|
73
|
+
return real_group.get_command(ctx, name)
|
|
74
|
+
|
|
75
|
+
# --- Lazy main group ---
|
|
76
|
+
class LazyMainGroup(click.Group):
|
|
77
|
+
def list_commands(self, ctx):
|
|
78
|
+
return COMMANDS.keys()
|
|
79
|
+
|
|
80
|
+
def get_command(self, ctx, name):
|
|
81
|
+
if name not in COMMANDS:
|
|
82
|
+
return None
|
|
83
|
+
module_path, attr_name = COMMANDS[name]["target"].split(":")
|
|
84
|
+
help_text = COMMANDS[name].get("help", None)
|
|
85
|
+
|
|
86
|
+
# If the attribute name ends with "_group", treat as LazyGroupCommand
|
|
87
|
+
if attr_name.endswith("_group"):
|
|
88
|
+
return LazyGroupCommand(module_path, attr_name, help_text)
|
|
89
|
+
else:
|
|
90
|
+
return LazyCommand(module_path, attr_name, help_text)
|
|
91
|
+
|
|
92
|
+
class LazyGroup(click.Group):
|
|
93
|
+
def list_commands(self, ctx):
|
|
94
|
+
return sorted(COMMANDS.keys())
|
|
95
|
+
|
|
96
|
+
def get_command(self, ctx, name):
|
|
97
|
+
if name not in COMMANDS:
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
# Split module path and attribute
|
|
101
|
+
module_path, attr_name = COMMANDS[name]["target"].split(":")
|
|
102
|
+
help_text = COMMANDS[name].get("help")
|
|
103
|
+
|
|
104
|
+
# Import module lazily
|
|
105
|
+
module = importlib.import_module(module_path)
|
|
106
|
+
cmd = getattr(module, attr_name)
|
|
107
|
+
|
|
108
|
+
# Attach help if missing
|
|
109
|
+
if help_text and getattr(cmd, "help", None) is None:
|
|
110
|
+
cmd.help = help_text
|
|
111
|
+
|
|
112
|
+
return cmd
|
|
113
|
+
|
|
114
|
+
# --- Main entrypoint ---
|
|
115
|
+
@click.group(cls=LazyMainGroup, invoke_without_command=True)
|
|
116
|
+
@click.version_option(version=__version__, prog_name="Agentify")
|
|
117
|
+
@click.pass_context
|
|
118
|
+
def main(ctx):
|
|
119
|
+
"""Agentify Toolkit CLI"""
|
|
120
|
+
# Show banner only if no subcommand is invoked
|
|
121
|
+
if ctx.invoked_subcommand is None:
|
|
122
|
+
console.print(
|
|
123
|
+
Panel(
|
|
124
|
+
agentify_icon,
|
|
125
|
+
title=f"AGENTIFY TOOLKIT CLI v{__version__}",
|
|
126
|
+
subtitle="Build, Run and deploy AI Agents declaratively",
|
|
127
|
+
border_style="white",
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
click.echo() # blank line
|
|
132
|
+
click.echo(ctx.command.get_help(ctx))
|
|
@@ -6,7 +6,6 @@ from .agent import agent_group
|
|
|
6
6
|
from .provider import provider_group
|
|
7
7
|
from .deploy import deploy_command
|
|
8
8
|
from .gateway import gateway_command
|
|
9
|
-
from ._mcp import xmcp_group
|
|
10
9
|
from .mcp import mcp_group
|
|
11
10
|
|
|
12
11
|
__all__ = [
|
|
@@ -19,5 +18,5 @@ __all__ = [
|
|
|
19
18
|
"provider_group",
|
|
20
19
|
"gateway_command",
|
|
21
20
|
"mcp_group",
|
|
22
|
-
"
|
|
21
|
+
"shell_comamnd"
|
|
23
22
|
]
|
|
@@ -108,7 +108,7 @@ def list_agents(path):
|
|
|
108
108
|
from rich.console import Console
|
|
109
109
|
from rich.table import Table
|
|
110
110
|
from rich.theme import Theme
|
|
111
|
-
from
|
|
111
|
+
from agentify.sdk.specs import load_agent_specs
|
|
112
112
|
|
|
113
113
|
console = Console(theme=Theme({"header": "bold cyan", "highlight": "magenta"}))
|
|
114
114
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from ..providers.rate_card import get_ratecard
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.table import Table
|
|
5
|
+
|
|
6
|
+
console = Console()
|
|
7
|
+
|
|
8
|
+
@click.group("provider")
|
|
9
|
+
def provider_group():
|
|
10
|
+
"""Manage model providers and API keys"""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@provider_group.command("add")
|
|
15
|
+
@click.argument("provider_name")
|
|
16
|
+
def add_provider(provider_name):
|
|
17
|
+
"""Add/Update model provider API keys in .env"""
|
|
18
|
+
from ..utils.env_manager import set_provider_key
|
|
19
|
+
set_provider_key(provider_name)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@provider_group.command("list")
|
|
23
|
+
def list_provider():
|
|
24
|
+
"""Lists registered model providers"""
|
|
25
|
+
|
|
26
|
+
from ..utils.env_manager import display_providers
|
|
27
|
+
display_providers()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@provider_group.command("remove")
|
|
31
|
+
@click.argument("provider_name")
|
|
32
|
+
def remove_provider(provider_name):
|
|
33
|
+
"""Remove a model provider"""
|
|
34
|
+
|
|
35
|
+
from ..utils.env_manager import remove_provider
|
|
36
|
+
remove_provider(provider_name)
|
|
37
|
+
|
|
38
|
+
@provider_group.command("validate")
|
|
39
|
+
@click.argument("provider_name")
|
|
40
|
+
def validate_provider(provider_name):
|
|
41
|
+
"""Validate the Provider API key"""
|
|
42
|
+
|
|
43
|
+
from ..utils.env_manager import validate_provider
|
|
44
|
+
# from rich.console import Console
|
|
45
|
+
# console = Console(force_terminal=True)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
with console.status(f"[yellow]Validating {provider_name}[/yellow]", spinner="dots", spinner_style="yellow"):
|
|
49
|
+
result = validate_provider(provider_name)
|
|
50
|
+
|
|
51
|
+
click.secho(f"✓ {provider_name} API KEY validated: {result}", fg="green")
|
|
52
|
+
# click.secho(f"✓ {provider_name.upper()}_API_KEY validated", fg="green")
|
|
53
|
+
|
|
54
|
+
except Exception as e:
|
|
55
|
+
click.secho(f"✗ Validation failed: {e}", fg="red")
|
|
56
|
+
raise SystemExit(1)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@provider_group.command("ratecard")
|
|
60
|
+
@click.argument("provider_name", required=False)
|
|
61
|
+
def get_provider_rate(provider_name):
|
|
62
|
+
"""Display provider rate card."""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# If provider_name is None → get all
|
|
66
|
+
ratecard = get_ratecard(provider_name)
|
|
67
|
+
|
|
68
|
+
if not ratecard:
|
|
69
|
+
console.print(f"[red]No rate card found for '{provider_name}'[/red]")
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
table_title = (
|
|
73
|
+
f"{provider_name.upper()} Rate Card"
|
|
74
|
+
if provider_name
|
|
75
|
+
else "All Providers Rate Card"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
table = Table(title=table_title)
|
|
79
|
+
|
|
80
|
+
table.add_column("Provider", style="cyan", no_wrap=True)
|
|
81
|
+
table.add_column("Model", style="white", no_wrap=True)
|
|
82
|
+
table.add_column("Input ($/1M)", justify="right", style="green")
|
|
83
|
+
table.add_column("Output ($/1M)", justify="right", style="magenta")
|
|
84
|
+
|
|
85
|
+
# CASE 1: Specific provider (shape = { model: rates })
|
|
86
|
+
if provider_name:
|
|
87
|
+
for model, rates in ratecard.items():
|
|
88
|
+
table.add_row(
|
|
89
|
+
provider_name,
|
|
90
|
+
model,
|
|
91
|
+
f"{rates['input_rate']:.2f}",
|
|
92
|
+
f"{rates['output_rate']:.2f}",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# CASE 2: All providers (shape = { provider: { model: rates } })
|
|
96
|
+
else:
|
|
97
|
+
for provider, models in ratecard.items():
|
|
98
|
+
for model, rates in models.items():
|
|
99
|
+
table.add_row(
|
|
100
|
+
provider,
|
|
101
|
+
model,
|
|
102
|
+
f"{rates['input_rate']:.2f}",
|
|
103
|
+
f"{rates['output_rate']:.2f}",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
console.print(table)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
@click.command("run")
|
|
5
|
+
@click.argument("path", required=False)
|
|
6
|
+
@click.option("--model", type=str, help="Override the model ID at runtime")
|
|
7
|
+
@click.option("--provider", type=str, help="Override the LLM provider at runtime")
|
|
8
|
+
@click.option("--server", type=str, help="Optional: run on a remote server instead of local")
|
|
9
|
+
@click.option("--debug", is_flag=True, help="Turn on debugging to see raw prompt")
|
|
10
|
+
@click.option("--toolprompt", is_flag=True, help="Agent prompts for approval before tool invocation")
|
|
11
|
+
@click.option("--showstats", is_flag=True, help="Display Token usage, cost and latency")
|
|
12
|
+
@click.option("--stream", is_flag=True, help="Stream response")
|
|
13
|
+
def run_command(path, model, provider, server, debug, toolprompt, showstats, stream):
|
|
14
|
+
"""Execute an agent from a YAML file or directory"""
|
|
15
|
+
import yaml
|
|
16
|
+
import sys
|
|
17
|
+
from agentify.sdk.agent import create_agent, create_agents
|
|
18
|
+
from agentify.sdk.specs import load_agent_specs
|
|
19
|
+
|
|
20
|
+
agent_path = path or "./agents"
|
|
21
|
+
path = Path(agent_path)
|
|
22
|
+
click.echo(f"Loading agents from: {path}")
|
|
23
|
+
|
|
24
|
+
if str(path.parent) not in sys.path:
|
|
25
|
+
sys.path.insert(0, str(path.parent))
|
|
26
|
+
|
|
27
|
+
if server:
|
|
28
|
+
if not path.is_file():
|
|
29
|
+
raise click.BadParameter("Remote run only supports a single YAML file")
|
|
30
|
+
click.echo(f"Would upload agent to server {server}")
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
if path.is_file():
|
|
34
|
+
with open(path, "r") as f:
|
|
35
|
+
spec = yaml.safe_load(f)
|
|
36
|
+
|
|
37
|
+
agent = create_agent(spec, provider=provider, model=model, agent_file=path.resolve())
|
|
38
|
+
agent.chat(debug=debug, toolprompt=toolprompt, showstats=showstats, stream=stream)
|
|
39
|
+
|
|
40
|
+
elif path.is_dir():
|
|
41
|
+
specs = load_agent_specs(path)
|
|
42
|
+
agents = create_agents(specs)
|
|
43
|
+
agent = show_agent_menu(agents)
|
|
44
|
+
agent.chat()
|
|
45
|
+
else:
|
|
46
|
+
raise click.BadParameter(f"Path does not exist: {path}")
|
|
47
|
+
|
|
48
|
+
from rich.console import Console
|
|
49
|
+
from rich.table import Table
|
|
50
|
+
|
|
51
|
+
def show_agent_menu(agents: dict) -> "Agent":
|
|
52
|
+
console = Console()
|
|
53
|
+
|
|
54
|
+
table = Table(title="Available Agents", header_style="bold cyan")
|
|
55
|
+
table.add_column("#", style="yellow", justify="right")
|
|
56
|
+
table.add_column("AgentName", style="green")
|
|
57
|
+
table.add_column("Agent Version", style="dim")
|
|
58
|
+
table.add_column("Agent Role", style="dim")
|
|
59
|
+
table.add_column("AI Provider", style="dim")
|
|
60
|
+
table.add_column("LLM Model", style="dim")
|
|
61
|
+
|
|
62
|
+
agent_list = list(agents.values())
|
|
63
|
+
|
|
64
|
+
for i, agent in enumerate(agent_list, start=1):
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
table.add_row(
|
|
68
|
+
str(i),
|
|
69
|
+
agent.name,
|
|
70
|
+
agent.version,
|
|
71
|
+
agent.description,
|
|
72
|
+
agent.provider,
|
|
73
|
+
agent.model_id,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
console.print(table)
|
|
77
|
+
|
|
78
|
+
while True:
|
|
79
|
+
choice = input("Select an agent: ").strip()
|
|
80
|
+
if choice.isdigit() and 1 <= int(choice) <= len(agent_list):
|
|
81
|
+
selected_agent = agent_list[int(choice) - 1]
|
|
82
|
+
return selected_agent
|
|
83
|
+
elif int(choice) == (len(agent_list) + 1):
|
|
84
|
+
console.print("Create custom Agent")
|
|
85
|
+
console.print("[red]Invalid selection[/red]")
|