Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions agentstack/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .cli import init_project_builder, configure_default_model, export_template
from .cli import init_project_builder, configure_default_model, export_template, serve_project
from .tools import list_tools, add_tool
from .run import run_project
from .run import run_project
17 changes: 14 additions & 3 deletions agentstack/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib
from typing import Optional
import os
import sys
Expand All @@ -19,17 +20,16 @@
from agentstack.logger import log
from agentstack import conf
from agentstack.conf import ConfigFile
from agentstack.utils import get_package_path
from agentstack.utils import get_package_path, get_framework, validator_not_empty
from agentstack.generation.files import ProjectFile
from agentstack import frameworks
from agentstack import generation
from agentstack import inputs
from agentstack.agents import get_all_agents
from agentstack.tasks import get_all_tasks
from agentstack.utils import open_json_file, term_color, is_snake_case, get_framework, validator_not_empty
from agentstack.proj_templates import TemplateConfig
from agentstack.exceptions import ValidationError

from agentstack.utils import open_json_file, term_color, is_snake_case, verify_agentstack_project

PREFERRED_MODELS = [
'openai/gpt-4o',
Expand Down Expand Up @@ -526,3 +526,14 @@
except Exception as e:
print(term_color(f"Failed to write template to file: {e}", 'red'))
sys.exit(1)


def serve_project():
verify_agentstack_project()

Check warning on line 532 in agentstack/cli/cli.py

View check run for this annotation

Codecov / codecov/patch

agentstack/cli/cli.py#L532

Added line #L532 was not covered by tests

# TODO: only silence output conditionally - maybe a debug or verbose option
os.system("docker stop agentstack-local > /dev/null 2>&1")
os.system("docker rm agentstack-local > /dev/null 2>&1")
with importlib.resources.path('agentstack.deploy', 'Dockerfile') as path:
os.system(f"docker build -t agent-service -f {path} .")
os.system("docker run --name agentstack-local -p 6969:6969 agent-service")

Check warning on line 539 in agentstack/cli/cli.py

View check run for this annotation

Codecov / codecov/patch

agentstack/cli/cli.py#L535-L539

Added lines #L535 - L539 were not covered by tests
7 changes: 7 additions & 0 deletions agentstack/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import sys
from agentstack.cli import init_project_builder, list_tools, configure_default_model, serve_project

Check warning on line 2 in agentstack/main.py

View check run for this annotation

Codecov / codecov/patch

agentstack/main.py#L2

Added line #L2 was not covered by tests
import argparse
import webbrowser

Expand Down Expand Up @@ -143,6 +144,9 @@

update = subparsers.add_parser('update', aliases=['u'], help='Check for updates', parents=[global_parser])

# 'serve' command
serve_parser = subparsers.add_parser('serve', aliases=['s'], help='Serve your agent')

Check warning on line 148 in agentstack/main.py

View check run for this annotation

Codecov / codecov/patch

agentstack/main.py#L148

Added line #L148 was not covered by tests

# Parse known args and store unknown args in extras; some commands use them later on
args, extra_args = parser.parse_known_args()

Expand Down Expand Up @@ -190,6 +194,9 @@
elif args.command in ["run", "r"]:
conf.assert_project()
run_project(command=args.function, debug=args.debug, cli_args=extra_args)
elif args.command in ['serve', 's']:
conf.assert_project()
serve_project()

Check warning on line 199 in agentstack/main.py

View check run for this annotation

Codecov / codecov/patch

agentstack/main.py#L198-L199

Added lines #L198 - L199 were not covered by tests
elif args.command in ['generate', 'g']:
conf.assert_project()
if args.generate_command in ['agent', 'a']:
Expand Down
35 changes: 35 additions & 0 deletions agentstack/serve/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Dockerfile
FROM python:3.11-slim

WORKDIR /app

# install git - TODO: remove after testing
RUN apt-get update && \
apt-get install -y git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Copy requirements first to leverage Docker cache
COPY pyproject.toml .
RUN pip install --no-cache-dir poetry
RUN pip install psutil flask

RUN #pip install agentstack
RUN pip install git+https://github.com/bboynton97/AgentStack.git@deploy
RUN mkdir src
RUN cp /usr/local/lib/python3.11/site-packages/agentstack/deploy/serve.py ./src

RUN pip uninstall -y agentstack

RUN apt-get update && apt-get install -y gcc
RUN POETRY_VIRTUALENVS_CREATE=false
RUN poetry config virtualenvs.create false && poetry install

# Copy the rest of the application
COPY . .

# Expose the port the app runs on
EXPOSE 6969

# Command to run the application
CMD ["python", "src/serve.py"]
83 changes: 83 additions & 0 deletions agentstack/serve/serve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# app.py
from dotenv import load_dotenv
load_dotenv(dotenv_path="/app/.env")

from flask import Flask, request, jsonify
import requests
from typing import Dict, Any
import os
from main import run

app = Flask(__name__)


def call_webhook(webhook_url: str, data: Dict[str, Any]) -> None:
"""Send results to the specified webhook URL."""
try:
response = requests.post(webhook_url, json=data)
response.raise_for_status()
except requests.exceptions.RequestException as e:
app.logger.error(f"Webhook call failed: {str(e)}")
raise


@app.route("/health", methods=["GET"])
def health():
return "Agent Server Up"


@app.route('/process', methods=['POST'])
def process_agent():
try:
# Extract data and webhook URL from request
request_data = request.get_json()
if not request_data or 'webhook_url' not in request_data:
return jsonify({'error': 'Missing webhook_url in request'}), 400

webhook_url = request_data.pop('webhook_url')

# Run the agent process with the provided data
# result = WebresearcherCrew().crew().kickoff(inputs=request_data)
# inputs = json.stringify(request_data)
# os.system(f"python src/main.py {inputs}")
result = run(request_data)

# Call the webhook with the results
call_webhook(webhook_url, {
'status': 'success',
'result': result
})

return jsonify({
'status': 'success',
'message': 'Agent process completed and webhook called'
})

except Exception as e:
error_message = str(e)
app.logger.error(f"Error processing request: {error_message}")

# Attempt to call webhook with error information
if webhook_url:
try:
call_webhook(webhook_url, {
'status': 'error',
'error': error_message
})
except:
pass # Webhook call failed, but we still want to return the error to the caller

return jsonify({
'status': 'error',
'error': error_message
}), 500


if __name__ == '__main__':
port = int(os.environ.get('PORT', 6969))

print("🚧 Running your agent on a development server")
print(f"Send agent requests to http://localhost:{port}")
print("Learn more about agent requests at https://docs.agentstack.sh/") # TODO: add docs for this

app.run(host='0.0.0.0', port=port)
Loading