Skip to content

Commit

Permalink
feat(cli): Finalize spec (broad strokes)
Browse files Browse the repository at this point in the history
Signed-off-by: Diwank Singh Tomer <[email protected]>
  • Loading branch information
creatorrr committed Jan 27, 2025
1 parent 4abb0c0 commit a0f2d9a
Show file tree
Hide file tree
Showing 9 changed files with 421 additions and 243 deletions.
6 changes: 3 additions & 3 deletions cli/julep_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from .agents import *
from .agents import agents_app as agents_app
from .app import app
from .auth import auth, get_config, save_config
from .chat import chat
from .init import init
from .run import run
from .sync import sync
from .tasks import *
from .tools import *
from .tasks import tasks_app as tasks_app
from .tools import tools_app as tools_app

__all__ = [
"app",
Expand Down
203 changes: 100 additions & 103 deletions cli/julep_cli/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,124 +8,108 @@

@agents_app.command()
def create(
name: Annotated[str, typer.Option("--name", "-n", help="Name of the agent")],
model: Annotated[str, typer.Option("--model", "-m", help="Model to be used by the agent")],
name: Annotated[str | None, typer.Option("--name", "-n", help="Name of the agent")] = None,
model: Annotated[
str | None, typer.Option("--model", "-m", help="Model to be used by the agent")
] = None,
about: Annotated[
str | None, typer.Option("--about", "-a", help="Description of the agent")
] = None,
metadata: Annotated[
str | None, typer.Option("--metadata", help="JSON metadata for the agent")
] = None,
default_settings: Annotated[
str | None,
typer.Option("--default-settings", help="JSON default settings for the agent"),
typer.Option("--default-settings", help="Default settings for the agent (JSON string)"),
] = None,
metadata: Annotated[
str | None, typer.Option("--metadata", help="Metadata for the agent (JSON string)")
] = None,
instructions: Annotated[
list[str], typer.Option("--instructions", help="Instructions for the agent")
] = [],
dry_run: Annotated[
bool,
list[str],
typer.Option(
"--dry-run",
"-d",
help="Simulate agent creation without making changes",
"--instructions", help="Instructions for the agent, can be specified multiple times"
),
] = False,
] = [],
definition: Annotated[
str | None, typer.Option("--definition", "-d", help="Path to an agent definition file")
] = None,
):
"""Create a new AI agent"""
"""Create a new AI agent. Either provide a definition file or use the other options."""
# Validate that either definition is provided or name/model
if not definition and not (name and model):
typer.echo("Error: Must provide either a definition file or name and model", err=True)
raise typer.Exit(1)

try:
metadata_dict = json.loads(metadata) if metadata else {}
settings_dict = json.loads(default_settings) if default_settings else {}
json.loads(metadata) if metadata else {}
json.loads(default_settings) if default_settings else {}
except json.JSONDecodeError as e:
typer.echo(f"Error parsing JSON: {e}", err=True)
raise typer.Exit(1)

if dry_run:
typer.echo("Dry run - would create agent with:")
typer.echo(f" Name: {name}")
typer.echo(f" Model: {model}")
typer.echo(f" About: {about}")
typer.echo(f" Metadata: {metadata_dict}")
typer.echo(f" Default Settings: {settings_dict}")
typer.echo(f" Instructions: {instructions}")
return

# TODO: Implement actual API call
typer.echo(f"Created agent '{name}' with model '{model}'")
if definition:
typer.echo(f"Created agent from definition file '{definition}'")
else:
typer.echo(f"Created agent '{name}' with model '{model}'")


@agents_app.command()
def update(
agent_id: Annotated[str, typer.Option("--id", "-i", help="ID of the agent to update")],
name: Annotated[str | None, typer.Option("--name", "-n", help="New name for the agent")] = None,
model: Annotated[str | None, typer.Option("--model", "-m", help="New model for the agent")] = None,
id: Annotated[str, typer.Option("--id", help="ID of the agent to update")],
name: Annotated[
str | None, typer.Option("--name", "-n", help="New name for the agent")
] = None,
model: Annotated[
str | None, typer.Option("--model", "-m", help="New model for the agent")
] = None,
about: Annotated[
str | None, typer.Option("--about", "-a", help="New description for the agent")
] = None,
dry_run: Annotated[
bool,
metadata: Annotated[
str | None, typer.Option("--metadata", help="Metadata for the agent (JSON string)")
] = None,
default_settings: Annotated[
str | None,
typer.Option("--default-settings", help="Default settings for the agent (JSON string)"),
] = None,
instructions: Annotated[
list[str],
typer.Option(
"--dry-run",
"-d",
help="Simulate agent update without making changes",
"--instructions", help="Instructions for the agent, can be specified multiple times"
),
] = False,
] = [],
):
"""Update an existing AI agent"""
"""Update an existing AI agent's details"""
try:
metadata_dict = json.loads(metadata) if metadata else {}
settings_dict = json.loads(default_settings) if default_settings else {}
except json.JSONDecodeError as e:
typer.echo(f"Error parsing JSON: {e}", err=True)
raise typer.Exit(1)

updates = {
k: v for k, v in {"name": name, "model": model, "about": about}.items() if v is not None
k: v
for k, v in {
"name": name,
"model": model,
"about": about,
"metadata": metadata_dict if metadata else None,
"default_settings": settings_dict if default_settings else None,
"instructions": instructions if instructions else None,
}.items()
if v is not None
}

if not updates:
typer.echo("No updates provided", err=True)
raise typer.Exit(1)

if dry_run:
typer.echo("Dry run - would update agent with:")
for key, value in updates.items():
typer.echo(f" {key}: {value}")
return

# TODO: Implement actual API call
typer.echo(f"Updated agent '{agent_id}'")


@agents_app.command()
def list(
filter: Annotated[
str | None, typer.Option("--filter", "-f", help="Filter agents based on criteria")
] = None,
metadata_filter: Annotated[
str | None,
typer.Option("--metadata-filter", help="Filter agents based on metadata criteria"),
] = None,
json_output: Annotated[
bool, typer.Option("--json", "-j", help="Output the list in JSON format")
] = False,
):
"""List all AI agents"""
# TODO: Implement actual API call
# Mock data for demonstration
agents = [
{"id": "agent1", "name": "Test Agent 1", "model": "gpt-4"},
{"id": "agent2", "name": "Test Agent 2", "model": "claude-3"},
]

if json_output:
typer.echo(json.dumps(agents, indent=2))
return

# Table format output
typer.echo("Available agents:")
typer.echo("ID\tName\tModel")
typer.echo("-" * 40)
for agent in agents:
typer.echo(f"{agent['id']}\t{agent['name']}\t{agent['model']}")
typer.echo(f"Updated agent '{id}'")


@agents_app.command()
def delete(
agent_id: Annotated[str, typer.Option("--id", "-i", help="ID of the agent to delete")],
id: Annotated[str, typer.Option("--id", help="ID of the agent to delete")],
force: Annotated[
bool,
typer.Option(
Expand All @@ -135,52 +119,65 @@ def delete(
),
] = False,
):
"""Delete an AI agent"""
"""Delete an existing AI agent"""
if not force:
confirm = typer.confirm(f"Are you sure you want to delete agent '{agent_id}'?")
confirm = typer.confirm(f"Are you sure you want to delete agent '{id}'?")
if not confirm:
typer.echo("Operation cancelled")
raise typer.Exit

# TODO: Implement actual API call
typer.echo(f"Deleted agent '{agent_id}'")
typer.echo(f"Deleted agent '{id}'")


@agents_app.command()
def reset(
agent_id: Annotated[str, typer.Option("--id", "-i", help="ID of the agent to reset")],
force: Annotated[
bool,
def list(
metadata_filter: Annotated[
str | None,
typer.Option(
"--force",
"-f",
help="Force reset without confirmation",
"--metadata-filter", help="Filter agents based on metadata criteria (JSON string)"
),
] = None,
json_output: Annotated[
bool, typer.Option("--json", help="Output the list in JSON format")
] = False,
):
"""Reset an AI agent to its initial state"""
if not force:
confirm = typer.confirm(f"Are you sure you want to reset agent '{agent_id}'?")
if not confirm:
typer.echo("Operation cancelled")
raise typer.Exit
"""List all AI agents or filter based on metadata"""
try:
json.loads(metadata_filter) if metadata_filter else {}
except json.JSONDecodeError as e:
typer.echo(f"Error parsing metadata filter JSON: {e}", err=True)
raise typer.Exit(1)

# TODO: Implement actual API call
typer.echo(f"Reset agent '{agent_id}' to initial state")
# Mock data for demonstration
agents = [
{"id": "agent1", "name": "Test Agent 1", "model": "gpt-4"},
{"id": "agent2", "name": "Test Agent 2", "model": "claude-3"},
]

if json_output:
typer.echo(json.dumps(agents, indent=2))
return

# Table format output
typer.echo("Available agents:")
typer.echo("ID\tName\tModel")
typer.echo("-" * 40)
for agent in agents:
typer.echo(f"{agent['id']}\t{agent['name']}\t{agent['model']}")


@agents_app.command()
def get(
agent_id: Annotated[str, typer.Option("--id", "-i", help="ID of the agent to retrieve")],
json_output: Annotated[
bool, typer.Option("--json", "-j", help="Output in JSON format")
] = False,
id: Annotated[str, typer.Option("--id", help="ID of the agent to retrieve")],
json_output: Annotated[bool, typer.Option("--json", help="Output in JSON format")] = False,
):
"""Get details of a specific AI agent"""
"""Get an agent by its ID"""
# TODO: Implement actual API call
# Mock data for demonstration
agent = {
"id": agent_id,
"id": id,
"name": "Test Agent",
"model": "gpt-4",
"about": "A test agent",
Expand Down
27 changes: 19 additions & 8 deletions cli/julep_cli/auth.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import os
from pathlib import Path
from typing import Annotated

Expand Down Expand Up @@ -38,22 +37,34 @@ def auth(
typer.Option(
"--api-key",
"-k",
help="Your Julep API key",
prompt="Please enter your Julep API key"
if not os.getenv("JULEP_API_KEY")
else False,
help="Your Julep API key for authentication",
prompt="Please enter your Julep API key (find this in your account settings)",
envvar="JULEP_API_KEY",
),
] = None,
environment: Annotated[
str,
typer.Option(
"--environment",
"-e",
help="Environment to use (defaults to production)",
),
] = "production",
):
"""Authenticate with the Julep platform"""
api_key = api_key or os.getenv("JULEP_API_KEY")
"""
Authenticate with the Julep platform.
Saves your API key to ~/.config/julep/config.yml for use with other commands.
The API key can be found in your Julep account settings.
"""

if not api_key:
typer.echo("No API key provided", err=True)
raise typer.Exit(1)

config = get_config()
config["api_key"] = api_key
config["environment"] = environment
save_config(config)

typer.echo("Successfully authenticated!")
typer.echo(f"Successfully authenticated with {environment} environment!")
37 changes: 19 additions & 18 deletions cli/julep_cli/chat.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pathlib import Path
import json
from typing import Annotated

import typer
Expand All @@ -8,29 +8,30 @@

@app.command()
def chat(
agent: Annotated[str, typer.Option("--agent", "-a", help="Agent ID or name to chat with")],
situation: Annotated[
str | None, typer.Option("--situation", "-s", help="Situation to chat about")
] = None,
history: Annotated[
Path | None,
agent: Annotated[
str,
typer.Option(
"--history",
"-h",
help="Load chat history from file",
"--agent",
"-a",
help="ID or name of the agent to chat with",
),
],
situation: Annotated[
str | None, typer.Option("--situation", "-s", help="Situation to chat about")
] = None,
save_history: Annotated[
Path | None,
typer.Option(
"--save-history",
"-s",
help="Save chat history to file",
),
settings: Annotated[
str | None,
typer.Option("--settings", help="Chat settings as a JSON string", parser=json.loads),
] = None,
):
"""Start an interactive chat session with an agent"""
"""
Initiate an interactive chat session with a specified AI agent.
The chat session runs in the terminal, allowing real-time conversation with the agent.
"""
# TODO: Implement chat logic
typer.echo(f"Starting chat with agent '{agent}'")
if situation:
typer.echo(f"Context: {situation}")
if settings:
typer.echo(f"Using custom settings: {settings}")
Loading

0 comments on commit a0f2d9a

Please sign in to comment.