Skip to content

Commit

Permalink
Merge branch 'wizard' of github.com:tcdent/AgentStack into wizard
Browse files Browse the repository at this point in the history
  • Loading branch information
bboynton97 committed Feb 10, 2025
2 parents 4cc52c8 + fa4f7ca commit d2b063f
Show file tree
Hide file tree
Showing 132 changed files with 3,289 additions and 1,369 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ ex/
**/ex/
cookiecutter.json

tests/tmp

examples/tests/
examples/tests/**/*

Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
recursive-include agentstack/templates *
recursive-include agentstack/frameworks/templates *
recursive-include agentstack/_tools *
include agentstack.json .env .env.example
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ AgentStack scaffolds your _agent stack_ - the tech stack that collectively is yo

### Currently Supported Providers
- **LLMs**: Most all notable LLMs and providers are supported via LiteLLM or LangChain
- **Framework**: Currently supported frameworks include CrewAI and LangGraph
- **Framework**: Currently supported frameworks include CrewAI, LangGraph, OpenAI Swarms and LlamaStack
- Roadmap: Pydantic AI, Eliza, AG2 and Autogen
- **Tools**: Maintaining the largest repository of framework-agnostic tools! All tools listed [here](https://docs.agentstack.sh/tools/community)
- **Observability**: AgentOps baked in by default with first-tier support
Expand Down
8 changes: 4 additions & 4 deletions agentstack/_tools/categories.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
{
"application-specific": {
"title": "Application Specific",
"description": "Tools that are specific to a particular application or domain."
},
"browsing": {
"title": "Browsing",
"description": "Tools that are used to browse the web."
Expand All @@ -19,6 +15,10 @@
"title": "Database",
"description": "Tools that are used to interact with databases."
},
"finance": {
"title": "Finance",
"description": "Tools that are used to interact with financial services."
},
"image-analysis": {
"title": "Image Analysis",
"description": "Tools that are used to analyze images."
Expand Down
2 changes: 1 addition & 1 deletion agentstack/_tools/file_read/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"category": "computer-control",
"tools": ["read_file"],
"description": "Read contents of files",
"url": "https://github.com/AgentOps-AI/AgentStack/tree/main/agentstack/tools/file_read",
"url": "https://docs.agentstack.sh/tools/tool/file_read",
"dependencies": []
}
209 changes: 209 additions & 0 deletions agentstack/_tools/payman/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import os
from typing import Dict, List, Optional, Union, Literal
from paymanai import Paymanai

# Initialize Payman client
PAYMAN_API_SECRET = os.getenv("PAYMAN_API_SECRET")
PAYMAN_ENVIRONMENT = os.getenv("PAYMAN_ENVIRONMENT", "sandbox")

client = Paymanai(
x_payman_api_secret=PAYMAN_API_SECRET,
environment=PAYMAN_ENVIRONMENT
)

def send_payment(
amount_decimal: float,
payment_destination_id: str,
customer_email: Optional[str] = None,
customer_id: Optional[str] = None,
customer_name: Optional[str] = None,
memo: Optional[str] = None
) -> Dict:
"""
Send USD from the agent's wallet to a pre-created payment destination.
Args:
amount_decimal: Amount to send in USD (e.g. 10.00 for $10.00)
payment_destination_id: ID of the pre-created payment destination
customer_email: Optional email address of the customer
customer_id: Optional ID of the customer
customer_name: Optional name of the customer
memo: Optional note or memo for the payment
Returns:
Dictionary containing payment details
"""
try:
return client.payments.send_payment(
amount_decimal=amount_decimal,
payment_destination_id=payment_destination_id,
customer_email=customer_email,
customer_id=customer_id,
customer_name=customer_name,
memo=memo
)
except Exception as e:
return {"error": f"Failed to send payment: {str(e)}"}

def search_destinations(
name: Optional[str] = None,
customer_id: Optional[str] = None,
contact_email: Optional[str] = None,
) -> List[Dict]:
"""
Search for existing payment destinations by name, customer, or email.
Args:
name: Optional name of the payment destination
customer_id: Optional customer ID who owns the destination
contact_email: Optional contact email to search for
Returns:
List of matching payment destinations with their IDs
"""
try:
return client.payments.search_destinations(
name=name,
customer_id=customer_id,
contact_email=contact_email
)
except Exception as e:
return [{"error": f"Failed to search destinations: {str(e)}"}]

def create_payee(
type: Literal["US_ACH", "PAYMAN_AGENT"],
name: str,
customer_id: Optional[str] = None,
account_holder_name: Optional[str] = None,
account_holder_type: Optional[Literal["individual", "business"]] = None,
account_number: Optional[str] = None,
routing_number: Optional[str] = None,
account_type: Optional[Literal["checking", "savings"]] = None,
payman_agent_id: Optional[str] = None,
contact_details: Optional[Dict] = None
) -> Dict:
"""
Create a new payment destination for future USD payments.
Args:
type: Type of payment destination ("US_ACH" or "PAYMAN_AGENT")
name: Name for the payment destination
customer_id: Customer ID who owns this destination (required for US_ACH)
account_holder_name: Name of the account holder (required for US_ACH)
account_holder_type: Type of account holder ("individual" or "business") (required for US_ACH)
account_number: Bank account number (required for US_ACH)
routing_number: Bank routing number (required for US_ACH)
account_type: Type of bank account ("checking" or "savings") (required for US_ACH)
payman_agent_id: The unique ID of the receiving agent (required for PAYMAN_AGENT)
contact_details: Optional dictionary containing contact information
Returns:
Dictionary containing the created payee details
"""
try:
params = {
"type": type,
"name": name,
"contact_details": contact_details
}

if type == "US_ACH":
params.update({
"customer_id": customer_id,
"account_holder_name": account_holder_name,
"account_holder_type": account_holder_type,
"account_number": account_number,
"routing_number": routing_number,
"account_type": account_type
})
elif type == "PAYMAN_AGENT":
params.update({
"payman_agent_id": payman_agent_id
})

return client.payments.create_payee(params)
except Exception as e:
return {"error": f"Failed to create payee: {str(e)}"}

def initiate_customer_deposit(
amount_decimal: float,
customer_id: str,
customer_email: Optional[str] = None,
customer_name: Optional[str] = None,
fee_mode: Optional[Literal["INCLUDED_IN_AMOUNT", "ADD_TO_AMOUNT"]] = None,
memo: Optional[str] = None,
wallet_id: Optional[str] = None
) -> Dict:
"""
Generate a checkout link for customer USD deposits.
Args:
amount_decimal: Amount to deposit in USD (e.g. 10.00 for $10.00)
customer_id: ID of the customer to deposit funds for
customer_email: Optional email address of the customer
customer_name: Optional name of the customer
fee_mode: How to handle processing fees ("INCLUDED_IN_AMOUNT" or "ADD_TO_AMOUNT")
memo: Optional memo for the transaction
wallet_id: Optional ID of specific wallet to deposit to
Returns:
Dictionary containing the checkout URL
"""
try:
response = client.payments.initiate_customer_deposit(
amount_decimal=amount_decimal,
customer_id=customer_id,
customer_email=customer_email,
customer_name=customer_name,
fee_mode=fee_mode,
memo=memo,
wallet_id=wallet_id
)
return response
except Exception as e:
return {"error": f"Failed to generate deposit link: {str(e)}"}

def get_customer_balance(
customer_id: str,
currency: Literal["USD"] = "USD"
) -> Dict:
"""
Check customer's available USD balance.
Args:
customer_id: ID of the customer to check balance for
currency: Currency code (always USD)
Returns:
Dictionary containing balance information
"""
try:
response = client.balances.get_customer_balance(customer_id, currency)
return {
"spendable_balance": response,
"currency": currency,
"customer_id": customer_id
}
except Exception as e:
return {"error": f"Failed to get customer balance: {str(e)}"}

def get_spendable_balance(
currency: Literal["USD"] = "USD"
) -> Dict:
"""
Check agent's available USD balance.
Args:
currency: Currency code (always USD)
Returns:
Dictionary containing balance information
"""
try:
response = client.balances.get_spendable_balance(currency)
return {
"spendable_balance": response,
"currency": currency
}
except Exception as e:
return {"error": f"Failed to get spendable balance: {str(e)}"}
18 changes: 18 additions & 0 deletions agentstack/_tools/payman/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "payman",
"category": "finance",
"tools": [
"send_payment",
"search_available_payees",
"add_payee",
"ask_for_money",
"get_balance"
],
"url": "https://www.paymanai.com",
"cta": "Setup your Agents Payman account at https://app.paymanai.com",
"env": {
"PAYMAN_API_SECRET": null,
"PAYMAN_ENVIRONMENT": null
},
"dependencies": ["paymanai>=2.1.0"]
}
2 changes: 1 addition & 1 deletion agentstack/_tools/stripe/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "stripe",
"url": "https://github.com/stripe/agent-toolkit",
"category": "application-specific",
"category": "finance",
"env": {
"STRIPE_SECRET_KEY": null
},
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "weaviate",
"url": "https://github.com/weaviate/weaviate-python-client",
"category": "vector-store",
"category": "database",
"env": {
"WEAVIATE_URL": null,
"WEAVIATE_API_KEY": null,
Expand Down
2 changes: 2 additions & 0 deletions agentstack/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ def __init__(self, name: str):

@property
def provider(self) -> str:
"""The LLM provider ie. 'openai' or 'openrouter'"""
return parse_provider_model(self.llm)[0]

@property
def model(self) -> str:
"""The model name ie. 'gpt-4o'"""
return parse_provider_model(self.llm)[1]

@property
Expand Down
6 changes: 4 additions & 2 deletions agentstack/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .cli import LOGO, configure_default_model, welcome_message, get_validated_input
from .cli import LOGO, configure_default_model, welcome_message, get_validated_input, parse_insertion_point
from .init import init_project
from .run import run_project
from .tools import list_tools, add_tool
from .tools import list_tools, add_tool, remove_tool
from .tasks import add_task
from .agents import add_agent
from .templates import insert_template, export_template
34 changes: 34 additions & 0 deletions agentstack/cli/agents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import Optional
from agentstack import conf
from agentstack import repo
from agentstack.cli import configure_default_model, parse_insertion_point
from agentstack import generation


def add_agent(
name: str,
role: Optional[str] = None,
goal: Optional[str] = None,
backstory: Optional[str] = None,
llm: Optional[str] = None,
position: Optional[str] = None,
):
"""
Add an agent to the user's project.
"""
conf.assert_project()
if not llm:
configure_default_model()
_position = parse_insertion_point(position)

repo.commit_user_changes()
with repo.Transaction() as commit:
commit.add_message(f"Added agent {name}")
generation.add_agent(
name=name,
role=role,
goal=goal,
backstory=backstory,
llm=llm,
position=_position,
)
5 changes: 4 additions & 1 deletion agentstack/cli/agentstack_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from datetime import datetime
from typing import Optional

from agentstack.utils import clean_input, get_version
from agentstack.utils import clean_input, get_version, snake_to_camel
from agentstack import log


Expand All @@ -11,6 +11,7 @@ def __init__(
self,
project_name: Optional[str] = None,
project_slug: Optional[str] = None,
class_name: Optional[str] = None,
description: str = "",
author_name: str = "",
version: str = "",
Expand All @@ -21,6 +22,7 @@ def __init__(
):
self.project_name = clean_input(project_name) if project_name else "myagent"
self.project_slug = clean_input(project_slug) if project_slug else self.project_name
self.class_name = snake_to_camel(self.project_slug) if not class_name else class_name
self.description = description
self.author_name = author_name
self.version = version
Expand All @@ -36,6 +38,7 @@ def to_dict(self):
return {
'project_name': self.project_name,
'project_slug': self.project_slug,
'class_name': self.class_name,
'description': self.description,
'author_name': self.author_name,
'version': self.version,
Expand Down
Loading

0 comments on commit d2b063f

Please sign in to comment.