agentify-toolkit 0.4.3a1__py3-none-any.whl
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/__init__.py +41 -0
- agentify/agentify.py +61 -0
- agentify/agents.py +37 -0
- agentify/cli.py +294 -0
- agentify/cli_config.py +100 -0
- agentify/cli_ui.py +44 -0
- agentify/providers/__init__.py +5 -0
- agentify/providers/anthropic.py +15 -0
- agentify/providers/bedrock.py +30 -0
- agentify/providers/google.py +10 -0
- agentify/providers/openai.py +11 -0
- agentify/providers/x.py +12 -0
- agentify/runtime_client.py +23 -0
- agentify/specs.py +19 -0
- agentify/ui/basic-chat.css +230 -0
- agentify/ui/chat.css +230 -0
- agentify/ui/chat.html +107 -0
- agentify/ui/htmx.min.js +1 -0
- agentify/ui/retro-chat.css +353 -0
- agentify/web.py +81 -0
- agentify_toolkit-0.4.3a1.dist-info/METADATA +345 -0
- agentify_toolkit-0.4.3a1.dist-info/RECORD +27 -0
- agentify_toolkit-0.4.3a1.dist-info/WHEEL +5 -0
- agentify_toolkit-0.4.3a1.dist-info/entry_points.txt +2 -0
- agentify_toolkit-0.4.3a1.dist-info/licenses/LICENSE +100 -0
- agentify_toolkit-0.4.3a1.dist-info/licenses/NOTICE +6 -0
- agentify_toolkit-0.4.3a1.dist-info/top_level.txt +1 -0
agentify/__init__.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright 2026 Backplane Software
|
|
3
|
+
Author: Lewis Sheridan
|
|
4
|
+
License: Apache License, Version 2.0
|
|
5
|
+
Description: Lightweight Python toolkit to build multi-model AI agents.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .agentify import Agent
|
|
9
|
+
from .agents import create_agent, create_agents
|
|
10
|
+
from .specs import load_agent_specs
|
|
11
|
+
from .cli_ui import show_agent_menu
|
|
12
|
+
from .web import run_web_ui
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"Agent",
|
|
16
|
+
"load_agent_specs",
|
|
17
|
+
"create_agent",
|
|
18
|
+
"create_agents",
|
|
19
|
+
"show_agent_menu"
|
|
20
|
+
"run_web_ui"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
__version__ = version("agentify-toolkit")
|
|
30
|
+
except PackageNotFoundError:
|
|
31
|
+
# Fallback when running locally from src/ (not installed)
|
|
32
|
+
__version__ = "0.0.0-dev"
|
|
33
|
+
except ImportError:
|
|
34
|
+
# Python <3.8 fallback
|
|
35
|
+
__version__ = "0.0.0-dev"
|
|
36
|
+
|
|
37
|
+
# Optional: mark as dev if running in source directory
|
|
38
|
+
if os.path.exists(os.path.join(os.path.dirname(__file__), "..", "pyproject.toml")):
|
|
39
|
+
# Indicates a local dev environment
|
|
40
|
+
if not __version__.endswith("-dev"):
|
|
41
|
+
__version__ += "-dev"
|
agentify/agentify.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright 2026 Backplane Software
|
|
3
|
+
Licensed under the Apache License, Version 2.0
|
|
4
|
+
Author: Lewis Sheridan
|
|
5
|
+
Description: Agentify class to build multi-model AI Agents
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from agentify.providers import run_openai, run_anthropic, run_google, run_bedrock, run_x
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.panel import Panel
|
|
14
|
+
from rich.prompt import Prompt
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class Agent:
|
|
19
|
+
name: str
|
|
20
|
+
description: str
|
|
21
|
+
provider: str
|
|
22
|
+
model_id: str
|
|
23
|
+
role: str
|
|
24
|
+
version: Optional[str] = field(default="0.0.0")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_model(self) -> str:
|
|
28
|
+
return self.model_id
|
|
29
|
+
|
|
30
|
+
def run(self, user_prompt: str) -> str:
|
|
31
|
+
match self.provider.lower():
|
|
32
|
+
case "openai":
|
|
33
|
+
return run_openai(self.model_id, user_prompt)
|
|
34
|
+
case "anthropic":
|
|
35
|
+
return run_anthropic(self.model_id, user_prompt)
|
|
36
|
+
case "google":
|
|
37
|
+
return run_google(self.model_id, user_prompt)
|
|
38
|
+
case "bedrock":
|
|
39
|
+
return run_bedrock(self.model_id, user_prompt)
|
|
40
|
+
case "x":
|
|
41
|
+
return run_x(self.model_id, user_prompt)
|
|
42
|
+
case _:
|
|
43
|
+
raise ValueError(f"Unsupported provider: {self.provider}")
|
|
44
|
+
|
|
45
|
+
def chat(agent: "Agent"):
|
|
46
|
+
console = Console()
|
|
47
|
+
console.print(Panel(
|
|
48
|
+
f"[bold cyan][/bold cyan]\n[bold cyan]{agent.name.upper()} [/bold cyan] [dim]{agent.version}[/dim]\nRole: {agent.description}\nUsing [yellow]{agent.model_id}[/yellow] by {agent.provider}",
|
|
49
|
+
border_style="cyan"
|
|
50
|
+
))
|
|
51
|
+
while True:
|
|
52
|
+
prompt = Prompt.ask("\nEnter your prompt ('/exit' to quit)").strip()
|
|
53
|
+
if prompt.lower() in ["/exit", "quit"]:
|
|
54
|
+
console.print("[yellow]Exiting. Goodbye![/yellow]")
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
full_prompt = f"You must assume the role of {agent.role} when responding to this prompt:\n\n{prompt}"
|
|
59
|
+
with console.status(f"[blue]Sending prompt to model... {agent.name} is thinking...[/blue]", spinner="dots"):
|
|
60
|
+
response = agent.run(full_prompt)
|
|
61
|
+
console.print(Panel.fit(response, title="Agent Response", border_style="green"))
|
agentify/agents.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright 2026 Backplane Software
|
|
2
|
+
# Licensed under the Apache License, Version 2.0
|
|
3
|
+
|
|
4
|
+
from agentify import Agent
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
def create_agents(specs: list) -> dict[str, Agent]:
|
|
8
|
+
agents = {}
|
|
9
|
+
for spec in specs:
|
|
10
|
+
agent = create_agent(spec)
|
|
11
|
+
agents[agent.name] = agent
|
|
12
|
+
return agents
|
|
13
|
+
|
|
14
|
+
def create_agent(spec: dict, provider: str = None, model: str = None) -> Agent:
|
|
15
|
+
"""
|
|
16
|
+
Create an Agent from a YAML/spec dictionary, optionally overriding model or provider.
|
|
17
|
+
"""
|
|
18
|
+
name = spec.get("name")
|
|
19
|
+
description = spec.get("description")
|
|
20
|
+
version = spec.get("version")
|
|
21
|
+
role = spec.get("role")
|
|
22
|
+
|
|
23
|
+
model_spec = spec.get("model", {})
|
|
24
|
+
model_id = model or model_spec.get("id")
|
|
25
|
+
provider = provider or model_spec.get("provider")
|
|
26
|
+
api_key_env = model_spec.get("api_key_env")
|
|
27
|
+
|
|
28
|
+
if api_key_env:
|
|
29
|
+
api_key = os.getenv(api_key_env)
|
|
30
|
+
# if not api_key:
|
|
31
|
+
# raise EnvironmentError(
|
|
32
|
+
# f"Environment variables '{api_key_env}' is not set"
|
|
33
|
+
# )
|
|
34
|
+
|
|
35
|
+
agent = Agent(name=name, provider=provider, model_id=model_id, role=role, description=description, version=version)
|
|
36
|
+
|
|
37
|
+
return agent
|
agentify/cli.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Copyright 2026 Backplane Software
|
|
2
|
+
# Licensed under the Apache License, Version 2.0
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import yaml
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
from agentify import __version__
|
|
10
|
+
from .specs import load_agent_specs
|
|
11
|
+
from .agents import create_agent, create_agents
|
|
12
|
+
|
|
13
|
+
from .cli_ui import show_agent_menu
|
|
14
|
+
from .cli_config import set_server, get_server, add_provider, remove_provider, list_providers
|
|
15
|
+
from .runtime_client import list_agents, upload_agent, delete_agent
|
|
16
|
+
|
|
17
|
+
from .web import run_web_ui
|
|
18
|
+
|
|
19
|
+
@click.group()
|
|
20
|
+
@click.version_option(version=__version__, prog_name="Agentify")
|
|
21
|
+
def main():
|
|
22
|
+
"""Agentify - Declarative AI Agents and Runtime Management"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
# -----------------------------
|
|
26
|
+
# Run local agents (existing logic)
|
|
27
|
+
# -----------------------------
|
|
28
|
+
@main.command()
|
|
29
|
+
@click.argument("path", required=False)
|
|
30
|
+
@click.option("--model", type=str, help="Override the model ID at runtime")
|
|
31
|
+
@click.option("--provider", type=str, help="Override the LLM provider at runtime")
|
|
32
|
+
@click.option("--server", type=str, help="Optional: run on a remote server instead of local")
|
|
33
|
+
@click.option("--web", is_flag=True, help="Run agent with web UI")
|
|
34
|
+
@click.option("--port", type=int, help="Set server port")
|
|
35
|
+
def run(path, provider, model, server, web, port):
|
|
36
|
+
"""
|
|
37
|
+
Run an agent YAML file or a folder containing agent YAMLs.
|
|
38
|
+
|
|
39
|
+
PATH can be:
|
|
40
|
+
- A single YAML file → runs that agent directly
|
|
41
|
+
- A folder containing YAML files → presents a menu to select an agent
|
|
42
|
+
"""
|
|
43
|
+
# Determine target path
|
|
44
|
+
agent_path = path or "./agents"
|
|
45
|
+
path = Path(agent_path)
|
|
46
|
+
click.echo(f"Loading agents from: {path}")
|
|
47
|
+
|
|
48
|
+
# If server override is provided, run via runtime API
|
|
49
|
+
if server:
|
|
50
|
+
if not path.is_file():
|
|
51
|
+
raise click.BadParameter("Remote run currently only supports a single YAML file")
|
|
52
|
+
resp = upload_agent(server, str(path))
|
|
53
|
+
click.echo(f"Agent uploaded and executed on server {server}: {resp}")
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
# ----- Local / programmatic agent logic -----
|
|
57
|
+
if path.is_file():
|
|
58
|
+
# Load YAML File
|
|
59
|
+
with open(path, "r") as f:
|
|
60
|
+
spec = yaml.safe_load(f)
|
|
61
|
+
|
|
62
|
+
agent = create_agent(spec, provider=provider, model=model)
|
|
63
|
+
|
|
64
|
+
if web:
|
|
65
|
+
run_web_ui(agent, port=port)
|
|
66
|
+
else:
|
|
67
|
+
agent.chat()
|
|
68
|
+
|
|
69
|
+
elif path.is_dir():
|
|
70
|
+
# Multi-agent mode
|
|
71
|
+
specs = load_agent_specs(path)
|
|
72
|
+
agents = create_agents(specs)
|
|
73
|
+
agent = show_agent_menu(agents)
|
|
74
|
+
agent.chat()
|
|
75
|
+
else:
|
|
76
|
+
raise click.BadParameter(f"Path does not exist: {path}")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# -----------------------------
|
|
80
|
+
# List local agents (interactive)
|
|
81
|
+
# -----------------------------
|
|
82
|
+
@main.command()
|
|
83
|
+
@click.argument("path", required=False)
|
|
84
|
+
def list(path):
|
|
85
|
+
"""
|
|
86
|
+
List agents in a folder and select one to run (interactive TUI)
|
|
87
|
+
"""
|
|
88
|
+
agent_path = path or "./agents"
|
|
89
|
+
path = Path(agent_path)
|
|
90
|
+
click.echo(f"Listing agents from: {path}")
|
|
91
|
+
|
|
92
|
+
if not path.is_dir():
|
|
93
|
+
raise click.BadParameter(f"Path is not a directory: {path}")
|
|
94
|
+
|
|
95
|
+
specs = load_agent_specs(path)
|
|
96
|
+
if not specs:
|
|
97
|
+
click.echo("No agent YAML files found.")
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
agents = create_agents(specs)
|
|
101
|
+
agent = show_agent_menu(agents)
|
|
102
|
+
agent.chat()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# -----------------------------
|
|
106
|
+
# Server configuration
|
|
107
|
+
# -----------------------------
|
|
108
|
+
@main.group()
|
|
109
|
+
def server():
|
|
110
|
+
"""Manage default runtime server configuration"""
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
@server.command("set")
|
|
114
|
+
@click.argument("url")
|
|
115
|
+
def server_set(url):
|
|
116
|
+
"""Set the default runtime server"""
|
|
117
|
+
set_server(url)
|
|
118
|
+
|
|
119
|
+
@server.command("show")
|
|
120
|
+
def server_show():
|
|
121
|
+
"""Show the current default runtime server"""
|
|
122
|
+
url = get_server()
|
|
123
|
+
if url:
|
|
124
|
+
click.echo(f"Default server: {url}")
|
|
125
|
+
else:
|
|
126
|
+
click.echo("No server configured.")
|
|
127
|
+
|
|
128
|
+
@main.group()
|
|
129
|
+
def config():
|
|
130
|
+
"""View or manage Agentify configuration"""
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
@config.command("show")
|
|
134
|
+
def config_show():
|
|
135
|
+
"""Show current Agentify configuration"""
|
|
136
|
+
import json
|
|
137
|
+
from agentify.cli_config import get_server
|
|
138
|
+
|
|
139
|
+
config_data = {
|
|
140
|
+
"server": get_server()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
click.echo(json.dumps(config_data, indent=4))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# -----------------------------
|
|
147
|
+
# Runtime server commands
|
|
148
|
+
# -----------------------------
|
|
149
|
+
@main.group()
|
|
150
|
+
def runtime():
|
|
151
|
+
"""Manage agents on a remote runtime server"""
|
|
152
|
+
pass
|
|
153
|
+
|
|
154
|
+
@runtime.command("list")
|
|
155
|
+
@click.option("--server", default=None, help="Override default server URL")
|
|
156
|
+
def show_server_agents(server):
|
|
157
|
+
"""List agents running on the runtime server"""
|
|
158
|
+
url = server or get_server()
|
|
159
|
+
if not url:
|
|
160
|
+
click.echo("No server configured. Use 'agentify server set <url>'")
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
agents = list_agents(url)
|
|
164
|
+
click.echo(f"{'NAME':20} {'STATUS':10} {'PROVIDER':10} {'MODEL'}")
|
|
165
|
+
for a in agents:
|
|
166
|
+
click.echo(f"{a['name']:20} {a['status']:10} {a['provider']:10} {a['model']}")
|
|
167
|
+
|
|
168
|
+
@runtime.command("show")
|
|
169
|
+
@click.argument("agent_name")
|
|
170
|
+
@click.option("--server", default=None, help="Override default server URL")
|
|
171
|
+
def runtime_show(agent_name, server):
|
|
172
|
+
"""Show details of a specific agent on the runtime server"""
|
|
173
|
+
url = server or get_server()
|
|
174
|
+
if not url:
|
|
175
|
+
click.echo("No server configured. Use 'agentify server set <url>'")
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
agent = list_agents(url, filter_name=agent_name) # or implement get_agent_details(agent_name)
|
|
179
|
+
if not agent:
|
|
180
|
+
click.echo(f"Agent not found: {agent_name}")
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
# Print detailed info
|
|
184
|
+
for a in agent:
|
|
185
|
+
click.echo(f"Name: {a['name']}")
|
|
186
|
+
click.echo(f"Status: {a['status']}")
|
|
187
|
+
click.echo(f"Provider: {a['provider']}")
|
|
188
|
+
click.echo(f"Model: {a['model']}")
|
|
189
|
+
click.echo(f"Version: {a.get('version', 'N/A')}")
|
|
190
|
+
click.echo("-" * 40)
|
|
191
|
+
|
|
192
|
+
@runtime.command("load")
|
|
193
|
+
@click.argument("path")
|
|
194
|
+
@click.option("--server", default=None, help="Override default server URL")
|
|
195
|
+
def upload(path, server):
|
|
196
|
+
"""Upload an agent YAML file to the runtime server"""
|
|
197
|
+
url = server or get_server()
|
|
198
|
+
if not url:
|
|
199
|
+
click.echo("No server configured. Use 'agentify server set <url>'")
|
|
200
|
+
return
|
|
201
|
+
resp = upload_agent(url, path)
|
|
202
|
+
click.echo(f"Uploaded {path} -> {url}: {resp}")
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@runtime.command("delete")
|
|
206
|
+
@click.argument("agent_name")
|
|
207
|
+
@click.option("--server", default=None, help="Override default server URL")
|
|
208
|
+
def delete(agent_name, server):
|
|
209
|
+
"""Delete an agent from the runtime server"""
|
|
210
|
+
url = server or get_server()
|
|
211
|
+
if not url:
|
|
212
|
+
click.echo("No server configured. Use 'agentify server set <url>'")
|
|
213
|
+
return
|
|
214
|
+
resp = delete_agent(url, agent_name)
|
|
215
|
+
click.echo(f"Deleted {agent_name} from {url}: {resp}")
|
|
216
|
+
|
|
217
|
+
@main.group()
|
|
218
|
+
def providers():
|
|
219
|
+
"""Add/Remote AI Provider API Keys"""
|
|
220
|
+
pass
|
|
221
|
+
|
|
222
|
+
@providers.command("add")
|
|
223
|
+
@click.argument("provider")
|
|
224
|
+
@click.option("--env", "env_var", help="Environment variable name")
|
|
225
|
+
@click.option("--key", help="API key (optional, will prompt if omitted)")
|
|
226
|
+
def providers_add(provider, env_var, key):
|
|
227
|
+
"""Add an AI Provider and API KEY"""
|
|
228
|
+
|
|
229
|
+
provider = provider.lower()
|
|
230
|
+
env_var = env_var or f"{provider.upper()}_API_KEY"
|
|
231
|
+
|
|
232
|
+
if not key:
|
|
233
|
+
key = click.prompt(
|
|
234
|
+
f"Enter API key for {provider}",
|
|
235
|
+
hide_input=True,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
add_provider(provider, env_var)
|
|
239
|
+
|
|
240
|
+
click.echo(f"✓ Provider '{provider}' added to local config\n")
|
|
241
|
+
click.echo("To apply in your current shell, run:\n")
|
|
242
|
+
click.echo(f"export {env_var}={key}")
|
|
243
|
+
|
|
244
|
+
@providers.command("list")
|
|
245
|
+
def providers_list():
|
|
246
|
+
"""List configured providers with their current status"""
|
|
247
|
+
|
|
248
|
+
providers = list_providers()
|
|
249
|
+
|
|
250
|
+
if not providers:
|
|
251
|
+
click.echo("No providers configured.")
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
# click.echo("Configured providers:\n")
|
|
255
|
+
# for name, cfg in providers.items():
|
|
256
|
+
# click.echo(f"• {name}")
|
|
257
|
+
# click.echo(f" env: {cfg['env']}\n")
|
|
258
|
+
|
|
259
|
+
click.echo("Configured providers:\n")
|
|
260
|
+
for name, cfg in providers.items():
|
|
261
|
+
env_var = cfg.get("env")
|
|
262
|
+
|
|
263
|
+
# Check if the env var is present in the current shell
|
|
264
|
+
if env_var in os.environ and os.environ[env_var]:
|
|
265
|
+
loaded = click.style("READY", fg="green") # green for ready
|
|
266
|
+
else:
|
|
267
|
+
loaded = click.style(
|
|
268
|
+
f"MISSING - run command: agentify providers add {name}", fg="yellow"
|
|
269
|
+
) # yellow for not set
|
|
270
|
+
|
|
271
|
+
click.echo(f"• {name}")
|
|
272
|
+
click.echo(f" env: {env_var}")
|
|
273
|
+
click.echo(f" status: {loaded}\n")
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
@providers.command("remove")
|
|
278
|
+
@click.argument("provider")
|
|
279
|
+
def providers_remove(provider):
|
|
280
|
+
"""Remove a configured providers"""
|
|
281
|
+
|
|
282
|
+
env_var = remove_provider(provider)
|
|
283
|
+
|
|
284
|
+
if not env_var:
|
|
285
|
+
click.echo(f"Provider not found: {provider}")
|
|
286
|
+
return
|
|
287
|
+
|
|
288
|
+
click.echo(f"✓ Provider '{provider}' removed from config\n")
|
|
289
|
+
click.echo("To remove from your current shell, run:\n")
|
|
290
|
+
click.echo(f"unset {env_var}")
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
if __name__ == "__main__":
|
|
294
|
+
main()
|
agentify/cli_config.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import yaml
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
AGENTIFY_DIR = Path.home() / ".agentify"
|
|
6
|
+
CONFIG_PATH = Path.home() / ".agentify" / "config.json"
|
|
7
|
+
PROVIDERS_FILE = AGENTIFY_DIR / "providers.yaml"
|
|
8
|
+
|
|
9
|
+
def load_config():
|
|
10
|
+
if CONFIG_PATH.exists():
|
|
11
|
+
return json.loads(CONFIG_PATH.read_text())
|
|
12
|
+
return {}
|
|
13
|
+
|
|
14
|
+
def save_config(config: dict):
|
|
15
|
+
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
16
|
+
CONFIG_PATH.write_text(json.dumps(config, indent=2))
|
|
17
|
+
|
|
18
|
+
def set_server(url: str):
|
|
19
|
+
config = load_config()
|
|
20
|
+
config["server_url"] = url
|
|
21
|
+
save_config(config)
|
|
22
|
+
print(f"Default server set to {url}")
|
|
23
|
+
|
|
24
|
+
def get_server(default=None):
|
|
25
|
+
config = load_config()
|
|
26
|
+
return config.get("server_url", default)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# -----------------------------
|
|
32
|
+
# Provider config
|
|
33
|
+
# -----------------------------
|
|
34
|
+
def load_providers():
|
|
35
|
+
"""
|
|
36
|
+
Load provider configuration from disk.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
dict: provider configuration
|
|
40
|
+
"""
|
|
41
|
+
if not PROVIDERS_FILE.exists():
|
|
42
|
+
return {}
|
|
43
|
+
|
|
44
|
+
with open(PROVIDERS_FILE, "r") as f:
|
|
45
|
+
return yaml.safe_load(f) or {}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def save_providers(data: dict):
|
|
49
|
+
"""
|
|
50
|
+
Persist provider configuration to disk.
|
|
51
|
+
"""
|
|
52
|
+
AGENTIFY_DIR.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
with open(PROVIDERS_FILE, "w") as f:
|
|
54
|
+
yaml.safe_dump(data, f)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def add_provider(provider: str, env_var: str):
|
|
58
|
+
"""
|
|
59
|
+
Register a provider and its environment variable.
|
|
60
|
+
"""
|
|
61
|
+
provider = provider.lower()
|
|
62
|
+
|
|
63
|
+
data = load_providers()
|
|
64
|
+
data.setdefault("providers", {})
|
|
65
|
+
data["providers"][provider] = {
|
|
66
|
+
"env": env_var
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
save_providers(data)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def remove_provider(provider: str):
|
|
73
|
+
"""
|
|
74
|
+
Remove a provider from configuration.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
str | None: env var name if provider existed
|
|
78
|
+
"""
|
|
79
|
+
provider = provider.lower()
|
|
80
|
+
data = load_providers()
|
|
81
|
+
providers = data.get("providers", {})
|
|
82
|
+
|
|
83
|
+
if provider not in providers:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
env_var = providers[provider]["env"]
|
|
87
|
+
del providers[provider]
|
|
88
|
+
save_providers(data)
|
|
89
|
+
return env_var
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def list_providers():
|
|
93
|
+
"""
|
|
94
|
+
Return configured providers.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
dict
|
|
98
|
+
"""
|
|
99
|
+
data = load_providers()
|
|
100
|
+
return data.get("providers", {})
|
agentify/cli_ui.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Copyright 2026 Backplane Software
|
|
2
|
+
# Licensed under the Apache License, Version 2.0
|
|
3
|
+
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.prompt import Prompt
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
def show_agent_menu(agents: dict) -> "Agent":
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
12
|
+
table = Table(title="Available Agents", header_style="bold cyan")
|
|
13
|
+
table.add_column("#", style="yellow", justify="right")
|
|
14
|
+
table.add_column("AgentName", style="green")
|
|
15
|
+
table.add_column("Agent Version", style="dim")
|
|
16
|
+
table.add_column("Agent Role", style="dim")
|
|
17
|
+
table.add_column("AI Provider", style="dim")
|
|
18
|
+
table.add_column("LLM Model", style="dim")
|
|
19
|
+
|
|
20
|
+
agent_list = list(agents.values())
|
|
21
|
+
|
|
22
|
+
for i, agent in enumerate(agent_list, start=1):
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
table.add_row(
|
|
26
|
+
str(i),
|
|
27
|
+
agent.name,
|
|
28
|
+
agent.version,
|
|
29
|
+
agent.description,
|
|
30
|
+
agent.provider,
|
|
31
|
+
agent.model_id,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
console.print(table)
|
|
35
|
+
|
|
36
|
+
while True:
|
|
37
|
+
choice = input("Select an agent: ").strip()
|
|
38
|
+
if choice.isdigit() and 1 <= int(choice) <= len(agent_list):
|
|
39
|
+
selected_agent = agent_list[int(choice) - 1]
|
|
40
|
+
return selected_agent
|
|
41
|
+
elif int(choice) == (len(agent_list) + 1):
|
|
42
|
+
console.print("Create custom Agent")
|
|
43
|
+
console.print("[red]Invalid selection[/red]")
|
|
44
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from anthropic import Anthropic
|
|
2
|
+
|
|
3
|
+
def run_anthropic(model_id: str, user_prompt: str) -> str:
|
|
4
|
+
client = Anthropic()
|
|
5
|
+
message = client.messages.create(
|
|
6
|
+
model= model_id,
|
|
7
|
+
max_tokens=1024,
|
|
8
|
+
messages=[
|
|
9
|
+
{
|
|
10
|
+
"role": "user",
|
|
11
|
+
"content": user_prompt
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
)
|
|
15
|
+
return message.content[0].text
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
def run_bedrock(model_id: str, user_prompt: str) -> str:
|
|
5
|
+
client = boto3.client(
|
|
6
|
+
service_name="bedrock-runtime",
|
|
7
|
+
region_name="eu-west-1"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
body = {
|
|
11
|
+
"anthropic_version": "bedrock-2023-05-31",
|
|
12
|
+
"max_tokens": 1024,
|
|
13
|
+
"temperature": 0.2,
|
|
14
|
+
"messages": [
|
|
15
|
+
{
|
|
16
|
+
"role": "user",
|
|
17
|
+
"content": user_prompt
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
response = client.invoke_model(
|
|
23
|
+
modelId=model_id,
|
|
24
|
+
body=json.dumps(body),
|
|
25
|
+
contentType="application/json",
|
|
26
|
+
accept="application/json"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
response_body = json.loads(response["body"].read())
|
|
30
|
+
return response_body["content"][0]["text"]
|
agentify/providers/x.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from xai_sdk import Client
|
|
3
|
+
from xai_sdk.chat import user, system
|
|
4
|
+
|
|
5
|
+
def run_x(model_id: str, user_prompt: str) -> str:
|
|
6
|
+
client = Client()
|
|
7
|
+
chat = client.chat.create(model=model_id)
|
|
8
|
+
chat.append(system("You are Grok, a highly intelligent, helpful AI assistant."))
|
|
9
|
+
chat.append(user(user_prompt))
|
|
10
|
+
response = chat.sample()
|
|
11
|
+
|
|
12
|
+
return response.content
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
|
|
3
|
+
def list_agents(server_url):
|
|
4
|
+
resp = requests.get(f"{server_url}/agents")
|
|
5
|
+
resp.raise_for_status()
|
|
6
|
+
return resp.json()
|
|
7
|
+
|
|
8
|
+
def upload_agent(server_url, yaml_file):
|
|
9
|
+
files = {'file': open(yaml_file, 'rb')}
|
|
10
|
+
resp = requests.post(f"{server_url}/agents", files=files)
|
|
11
|
+
resp.raise_for_status()
|
|
12
|
+
return resp.json()
|
|
13
|
+
|
|
14
|
+
def run_agent(server_url, yaml_file):
|
|
15
|
+
files = {'file': open(yaml_file, 'rb')}
|
|
16
|
+
resp = requests.post(f"{server_url}/agents/run", files=files)
|
|
17
|
+
resp.raise_for_status()
|
|
18
|
+
return resp.json()
|
|
19
|
+
|
|
20
|
+
def delete_agent(server_url, agent_name):
|
|
21
|
+
resp = requests.delete(f"{server_url}/agents/{agent_name}")
|
|
22
|
+
resp.raise_for_status()
|
|
23
|
+
return resp.json()
|