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.
Files changed (93) hide show
  1. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/PKG-INFO +2 -1
  2. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/pyproject.toml +2 -1
  3. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/__init__.py +1 -1
  4. agentify_toolkit-0.22.0/src/agentify/_bin/_delete_cli.py +132 -0
  5. agentify_toolkit-0.22.0/src/agentify/cli/__init__.py +3 -0
  6. agentify_toolkit-0.22.0/src/agentify/cli/main.py +132 -0
  7. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/__init__.py +1 -2
  8. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/agent.py +1 -1
  9. agentify_toolkit-0.22.0/src/agentify/commands/provider.py +106 -0
  10. agentify_toolkit-0.22.0/src/agentify/commands/run.py +85 -0
  11. agentify_toolkit-0.22.0/src/agentify/commands/runtime.py +227 -0
  12. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/serve.py +1 -1
  13. agentify_toolkit-0.22.0/src/agentify/commands/shell.py +7 -0
  14. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/tool.py +1 -1
  15. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/gateway/server.py +12 -4
  16. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/builtin_tools.py +1 -1
  17. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/client.py +21 -8
  18. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/registry.py +1 -1
  19. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/server.py +3 -3
  20. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/providers/__init__.py +2 -1
  21. agentify_toolkit-0.22.0/src/agentify/providers/agentify.py +47 -0
  22. agentify_toolkit-0.22.0/src/agentify/providers/anthropic.py +80 -0
  23. agentify_toolkit-0.22.0/src/agentify/providers/bedrock.py +107 -0
  24. agentify_toolkit-0.22.0/src/agentify/providers/deepseek.py +78 -0
  25. agentify_toolkit-0.22.0/src/agentify/providers/github.py +115 -0
  26. agentify_toolkit-0.22.0/src/agentify/providers/google.py +95 -0
  27. agentify_toolkit-0.22.0/src/agentify/providers/mistral.py +83 -0
  28. agentify_toolkit-0.22.0/src/agentify/providers/ollama.py +69 -0
  29. agentify_toolkit-0.22.0/src/agentify/providers/ollama_local.py +66 -0
  30. agentify_toolkit-0.22.0/src/agentify/providers/openai.py +70 -0
  31. agentify_toolkit-0.22.0/src/agentify/providers/rate_card.py +71 -0
  32. agentify_toolkit-0.22.0/src/agentify/providers/x.py +70 -0
  33. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/runtime/server.py +27 -7
  34. agentify_toolkit-0.22.0/src/agentify/sdk/__init__.py +0 -0
  35. agentify_toolkit-0.22.0/src/agentify/sdk/agent.py +564 -0
  36. agentify_toolkit-0.22.0/src/agentify/shell/app.py +461 -0
  37. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/utils/env_manager.py +4 -4
  38. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/PKG-INFO +2 -1
  39. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/SOURCES.txt +12 -13
  40. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/requires.txt +1 -0
  41. agentify_toolkit-0.19.0/src/agentify/_cli.py +0 -662
  42. agentify_toolkit-0.19.0/src/agentify/_tool.py +0 -147
  43. agentify_toolkit-0.19.0/src/agentify/agent.py +0 -352
  44. agentify_toolkit-0.19.0/src/agentify/cli.py +0 -57
  45. agentify_toolkit-0.19.0/src/agentify/commands/_mcp.py +0 -183
  46. agentify_toolkit-0.19.0/src/agentify/commands/provider.py +0 -51
  47. agentify_toolkit-0.19.0/src/agentify/commands/run.py +0 -45
  48. agentify_toolkit-0.19.0/src/agentify/commands/runtime.py +0 -101
  49. agentify_toolkit-0.19.0/src/agentify/headers.py +0 -45
  50. agentify_toolkit-0.19.0/src/agentify/mcp_client.py +0 -23
  51. agentify_toolkit-0.19.0/src/agentify/mcpserver/__init__.py +0 -1
  52. agentify_toolkit-0.19.0/src/agentify/mcpserver/server.py +0 -237
  53. agentify_toolkit-0.19.0/src/agentify/providers/agentify.py +0 -42
  54. agentify_toolkit-0.19.0/src/agentify/providers/anthropic.py +0 -27
  55. agentify_toolkit-0.19.0/src/agentify/providers/bedrock.py +0 -30
  56. agentify_toolkit-0.19.0/src/agentify/providers/deepseek.py +0 -26
  57. agentify_toolkit-0.19.0/src/agentify/providers/github.py +0 -39
  58. agentify_toolkit-0.19.0/src/agentify/providers/google.py +0 -22
  59. agentify_toolkit-0.19.0/src/agentify/providers/mistral.py +0 -26
  60. agentify_toolkit-0.19.0/src/agentify/providers/ollama.py +0 -35
  61. agentify_toolkit-0.19.0/src/agentify/providers/ollama_local.py +0 -25
  62. agentify_toolkit-0.19.0/src/agentify/providers/openai.py +0 -22
  63. agentify_toolkit-0.19.0/src/agentify/providers/x.py +0 -23
  64. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/LICENSE +0 -0
  65. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/NOTICE +0 -0
  66. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/README.md +0 -0
  67. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/setup.cfg +0 -0
  68. /agentify_toolkit-0.19.0/src/agentify/cli_ui.py → /agentify_toolkit-0.22.0/src/agentify/_bin/_delete_cli_ui.py +0 -0
  69. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/cli_config.py +0 -0
  70. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/config.py +0 -0
  71. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/deploy.py +0 -0
  72. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/gateway.py +0 -0
  73. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/commands/mcp.py +0 -0
  74. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/mcp/__init__.py +0 -0
  75. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/providers/backplane.py +0 -0
  76. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/runtime/__init__.py +0 -0
  77. {agentify_toolkit-0.19.0/src/agentify → agentify_toolkit-0.22.0/src/agentify/runtime}/runtime_client.py +0 -0
  78. {agentify_toolkit-0.19.0/src/agentify → agentify_toolkit-0.22.0/src/agentify/sdk}/specs.py +0 -0
  79. {agentify_toolkit-0.19.0/src/agentify → agentify_toolkit-0.22.0/src/agentify/sdk}/tool.py +0 -0
  80. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/server/__init__.py +0 -0
  81. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/server/server.py +0 -0
  82. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/agent_list.css +0 -0
  83. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/agent_list.html +0 -0
  84. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/basic-chat.css +0 -0
  85. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/chat.css +0 -0
  86. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/chat.html +0 -0
  87. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/fun_agent_list.html +0 -0
  88. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/htmx.min.js +0 -0
  89. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/retro-chat.css +0 -0
  90. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify/ui/runtime_chat.html +0 -0
  91. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/dependency_links.txt +0 -0
  92. {agentify_toolkit-0.19.0 → agentify_toolkit-0.22.0}/src/agentify_toolkit.egg-info/entry_points.txt +0 -0
  93. {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.19.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.19.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",
@@ -24,5 +24,5 @@ if os.path.exists(os.path.join(os.path.dirname(__file__), "..", "pyproject.toml"
24
24
  if not __version__.endswith("-dev"):
25
25
  __version__ += "-dev"
26
26
 
27
- from .agent import Agent
27
+ from agentify.sdk.agent import Agent
28
28
  __all__ = ["Agent"]
@@ -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,3 @@
1
+ from .main import main
2
+
3
+ __all__ = ["main"]
@@ -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
- "xmcp_group"
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 ..specs import load_agent_specs
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]")