Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
aa87a26
Support Plugin architechture for camel-ai, langchain, crew-ai WIP (ne…
js-ts Feb 25, 2025
4c688a0
minor fixes
js-ts Feb 25, 2025
927d193
add camel-ai
js-ts Feb 25, 2025
ce28c07
minor fixes
js-ts Feb 26, 2025
20cb157
minor fix
js-ts Feb 26, 2025
71a5d1d
Fix langchain
js-ts Feb 26, 2025
7b891de
Add config related code for crewai plugin
js-ts Feb 28, 2025
1141694
template fixes
js-ts Mar 2, 2025
6b1972c
template update
js-ts Mar 4, 2025
dbc11b2
Fix name
js-ts Mar 4, 2025
85c38bb
add 's'
js-ts Mar 4, 2025
e36fada
Plugin dir create fix
js-ts Mar 4, 2025
2e39000
remove debbuging logs
js-ts Mar 4, 2025
1443aab
First publish to ipfs and then register
js-ts Mar 4, 2025
8aa68fb
remove symlink
js-ts Mar 5, 2025
865f556
Comment out code which publishes to the hub when your run poetry run …
js-ts Mar 6, 2025
90298ce
fix
js-ts Mar 6, 2025
e7aaa08
import fix
js-ts Mar 6, 2025
efc7254
uncomment
js-ts Mar 6, 2025
70fce08
Fixes
Mar 8, 2025
82ac77e
exclude *.pem from being added.
Mar 10, 2025
47cd2cb
Comment out code which publishes to the hub when your run poetry run …
js-ts Mar 6, 2025
a9a117b
migrate to uv
Mar 10, 2025
e446add
Revert "Comment out code which publishes to the hub when your run poe…
Mar 10, 2025
d676326
Reapply "Comment out code which publishes to the hub when your run po…
Mar 10, 2025
080a913
Revert " migrate to uv"
Mar 10, 2025
362b068
Migrate from pdm to default hatchling
Mar 10, 2025
d024581
Migrate modules to uv
Mar 11, 2025
ecd0663
add tag and release to gh publishing
Mar 11, 2025
831bfd0
fix tag already exist error
Mar 11, 2025
22984b6
Fix configs issue
Mar 13, 2025
97730e0
PEP 508 compatible dependency specifier string.
Mar 13, 2025
cd39291
exclude db
Mar 13, 2025
aafd6d2
switch to hatchling
Mar 13, 2025
2a87b64
Allow direct references
Mar 13, 2025
2969d40
remove uv.lock from .gitignore
js-ts Mar 13, 2025
924ca89
keep db folder
js-ts Mar 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,7 @@ cython_debug/
#.idea/
.DS_Store

*.pem
*.pem

examples/
new_examples/
34 changes: 32 additions & 2 deletions naptha_sdk/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
from rich.table import Table
from rich import box
import json
import importlib.metadata
import shutil
from git import Repo
from pathlib import Path
from naptha_sdk.client.plugin import PluginCLI

from naptha_sdk.client.hub import user_setup_flow
from naptha_sdk.client.naptha import Naptha
Expand All @@ -22,6 +27,7 @@
from naptha_sdk.utils import url_to_node, get_env_data, get_logger
from naptha_sdk.secrets import create_secret, verify_and_reconstruct_rsa_key

load_dotenv(override=True)
logger = get_logger(__name__)

async def list_nodes(naptha):
Expand Down Expand Up @@ -727,6 +733,17 @@ async def main():
personas_parser.add_argument("-u", '--update', type=str, help='Metadata in "key=value" format')
personas_parser.add_argument('-d', '--delete', action='store_true', help='Delete a persona')

# Plugin parser
plugin_parser = subparsers.add_parser("plugins", help="Manage plugins")
plugin_subparsers = plugin_parser.add_subparsers(dest="plugin_cmd", required=True)
add_parser = plugin_subparsers.add_parser("add", help="Add a plugin from Git repository")
add_parser.add_argument("-u", "--url", required=True, help="Git repository URL")
remove_parser = plugin_subparsers.add_parser("remove", help="Remove an installed plugin")
remove_parser.add_argument("-n", "--name", required=True, help="Plugin name to remove")
update_parser = plugin_subparsers.add_parser("update", help="Update plugins")
update_parser.add_argument("-n", "--name", help="Specific plugin to update (omit for all)")
list_parser = plugin_subparsers.add_parser("list", help="List installed plugins")

# Tool parser
tools_parser = subparsers.add_parser("tools", help="List available tools.")
tools_parser.add_argument('module_name', nargs='?', help='Optional tool name')
Expand Down Expand Up @@ -811,6 +828,7 @@ async def main():
const=True,
metavar="URL")
publish_parser.add_argument("-s", "--subdeployments", help="Publish subdeployments", action="store_true")
publish_parser.add_argument("-gh", "--github", help="Publish to GitHub", action="store_true")

# Add API Key Command
deploy_secrets_parser = subparsers.add_parser("deploy-secrets", help="Add API keys or tokens.")
Expand All @@ -830,7 +848,7 @@ async def main():
elif args.command in [
"nodes", "agents", "orchestrators", "environments",
"personas", "kbs", "memories", "tools", "run", "inference",
"publish", "create", "storage", "deploy-secrets"
"publish", "create", "storage", "deploy-secrets", "plugins"
]:
if not naptha.hub.is_authenticated:
if not hub_username or not hub_password:
Expand Down Expand Up @@ -877,6 +895,18 @@ async def main():
await naptha.hub.create_module("orchestrator", module_config)
else:
print("Invalid command.")

elif args.command == "plugins":
if args.plugin_cmd == "add":
await PluginCLI.add_plugin(naptha, args.url)
elif args.plugin_cmd == "remove":
await PluginCLI.remove_plugin(naptha, args.name)
elif args.plugin_cmd == "update":
await PluginCLI.update_plugin(naptha, args.name)
elif args.plugin_cmd == "list":
await PluginCLI.list_plugins(naptha)
else:
print("Invalid command.")
elif args.command == "environments":
if not args.module_name:
await list_modules(naptha, module_type='environment')
Expand Down Expand Up @@ -986,7 +1016,7 @@ async def main():
file=args.file
)
elif args.command == "publish":
await naptha.publish_modules(args.decorator, args.register, args.subdeployments)
await naptha.publish_modules(args.decorator, args.register, args.subdeployments, args.github)
elif args.command == "deploy-secrets":
public_key = await get_server_public_key(naptha)
existing_secrets = await list_secrets(naptha)
Expand Down
576 changes: 525 additions & 51 deletions naptha_sdk/client/naptha.py

Large diffs are not rendered by default.

108 changes: 108 additions & 0 deletions naptha_sdk/client/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from pathlib import Path
import shutil
from git import Repo
from rich.table import Table
from rich.console import Console
import json
from naptha_sdk.module_manager import plugin_manager

class PluginCLI:
@staticmethod
async def add_plugin(naptha, url: str):
"""Add a plugin from Git repository URL"""
try:
plugin_dir = Path("~/.naptha/plugins").expanduser()
plugin_dir.mkdir(parents=True, exist_ok=True)

repo_name = url.split("/")[-1].replace(".git", "")
dest_path = plugin_dir / repo_name

if dest_path.exists():
print(f"Plugin {repo_name} already exists. Use 'update' to refresh.")
return

print(f"Cloning plugin from {url}...")
Repo.clone_from(url, str(dest_path))
print(f"Successfully added plugin: {repo_name}")

# Reload plugins after addition
plugin_manager.load_plugins()

except Exception as e:
print(f"Plugin addition failed: {str(e)}")

@staticmethod
async def remove_plugin(naptha, name: str):
"""Remove an installed plugin"""
try:
plugin_dir = Path("~/.naptha/plugins").expanduser() / name

if not plugin_dir.exists():
print(f"Plugin {name} not found")
return

shutil.rmtree(plugin_dir)
print(f"Successfully removed plugin: {name}")

# Reload plugins after removal
plugin_manager.load_plugins()

except Exception as e:
print(f"Plugin removal failed: {str(e)}")

@staticmethod
async def update_plugin(naptha, name: str = None):
"""Update one or all plugins"""
try:
plugin_base = Path("~/.naptha/plugins").expanduser()

if name:
plugins = [plugin_base / name]
else:
plugins = [d for d in plugin_base.iterdir() if d.is_dir()]

updated = []
for plugin_dir in plugins:
if not (plugin_dir / ".git").exists():
print(f"Skipping {plugin_dir.name} (not a Git repository)")
continue

print(f"Updating {plugin_dir.name}...")
repo = Repo(plugin_dir)
repo.remotes.origin.pull()
updated.append(plugin_dir.name)

if updated:
print(f"Successfully updated: {', '.join(updated)}")
plugin_manager.load_plugins()
else:
print("No plugins updated")

except Exception as e:
print(f"Plugin update failed: {str(e)}")

@staticmethod
async def list_plugins(naptha):
"""List all installed plugins"""
table = Table(title="Installed Plugins")
table.add_column("Name", style="cyan")
table.add_column("Type", style="magenta")
table.add_column("Version", style="green")
table.add_column("Path", style="yellow")

plugin_dir = Path("~/.naptha/plugins").expanduser()

for plugin_path in plugin_dir.iterdir():
if plugin_path.is_dir():
metadata_path = plugin_path / "metadata.json"
if metadata_path.exists():
with open(metadata_path) as f:
metadata = json.load(f)
table.add_row(
plugin_path.name,
metadata.get("plugin_type", "unknown"),
metadata.get("sdk_version", "unknown"),
str(plugin_path)
)

Console().print(table)
Loading