Skip to main content

A Python SDK for the Jules API

Project description

Jules Agent SDK

A user-friendly Python SDK for the Jules API. This SDK provides a clean, Pythonic interface for interacting with Jules sessions, activities, and sources.

Features

  • 🚀 Simple and intuitive API - Easy-to-use client with straightforward methods
  • 📦 Modular design - Organized into logical modules (sessions, activities, sources)
  • 🔄 Async support - Full support for async/await with aiohttp
  • 🛡️ Type hints - Complete type annotations for better IDE support
  • Error handling - Clear, descriptive exceptions for different error cases
  • 📖 Well documented - Comprehensive docstrings and examples

Installation

Install the package via pip:

pip install jules-agent-sdk

For development with testing dependencies:

pip install jules-agent-sdk[dev]

Quick Start

Basic Usage (Synchronous)

from jules_agent_sdk import JulesClient

# Initialize the client
client = JulesClient(api_key="your-api-key")

# Create a new session
session = client.sessions.create(
    prompt="Fix the authentication bug in the login module",
    source="sources/my-github-repo-id",
    starting_branch="main"
)

print(f"Session created: {session.id}")
print(f"Session state: {session.state}")

# Wait for the session to complete
completed_session = client.sessions.wait_for_completion(session.id)
print(f"Final state: {completed_session.state}")

# List all activities for the session
result = client.activities.list_all(session.id)
for activity in result:
    print(f"Activity: {activity.description}")

# Don't forget to close the client when done
client.close()

Using Context Manager

from jules_agent_sdk import JulesClient

# Automatically handles cleanup
with JulesClient(api_key="your-api-key") as client:
    session = client.sessions.create(
        prompt="Add user authentication",
        source="sources/repo-id",
        starting_branch="develop"
    )
    print(f"Session: {session.id}")

Async Usage

import asyncio
from jules_agent_sdk import AsyncJulesClient

async def main():
    async with AsyncJulesClient(api_key="your-api-key") as client:
        # Create session
        session = await client.sessions.create(
            prompt="Refactor the database layer",
            source="sources/my-repo",
            starting_branch="main"
        )

        # Wait for completion
        completed = await client.sessions.wait_for_completion(session.id)

        # Get all activities
        activities = await client.activities.list_all(session.id)
        for activity in activities:
            print(f"Activity: {activity.description}")

asyncio.run(main())

API Reference

Client Initialization

from jules_agent_sdk import JulesClient, AsyncJulesClient

# Synchronous client
client = JulesClient(api_key="your-api-key")

# Async client
async_client = AsyncJulesClient(api_key="your-api-key")

# Custom base URL (optional)
client = JulesClient(
    api_key="your-api-key",
    base_url="https://custom-api-endpoint.com/v1alpha"
)

Sessions API

Create a Session

session = client.sessions.create(
    prompt="Your task description",
    source="sources/source-id",
    starting_branch="main",  # Optional, for GitHub repos
    title="Optional Session Title",  # Optional
    require_plan_approval=False  # Optional, defaults to False
)

Get a Session

session = client.sessions.get("session-id")
print(session.state)  # SessionState enum
print(session.url)    # Web UI URL

List Sessions

# List with pagination
result = client.sessions.list(page_size=10)
for session in result['sessions']:
    print(session.id, session.state)

# Get next page
if result['nextPageToken']:
    next_result = client.sessions.list(page_token=result['nextPageToken'])

Approve a Plan

client.sessions.approve_plan("session-id")

Send a Message

client.sessions.send_message(
    session_id="session-id",
    prompt="Please also add unit tests"
)

Wait for Completion

# Poll until session completes or fails
final_session = client.sessions.wait_for_completion(
    session_id="session-id",
    poll_interval=5,  # seconds between polls
    timeout=3600      # optional timeout in seconds
)

Activities API

Get an Activity

activity = client.activities.get(
    session_id="session-id",
    activity_id="activity-id"
)

List Activities

# With pagination
result = client.activities.list(
    session_id="session-id",
    page_size=20
)

for activity in result['activities']:
    print(activity.description)

    # Check activity type
    if activity.agent_messaged:
        print(f"Agent message: {activity.agent_messaged['agentMessage']}")
    elif activity.plan_generated:
        plan = activity.plan_generated['plan']
        print(f"Plan steps: {len(plan['steps'])}")

List All Activities

# Automatically handles pagination
all_activities = client.activities.list_all("session-id")
print(f"Total activities: {len(all_activities)}")

Sources API

Get a Source

source = client.sources.get("source-id")

if source.github_repo:
    print(f"Repo: {source.github_repo.owner}/{source.github_repo.repo}")
    print(f"Default branch: {source.github_repo.default_branch.display_name}")

List Sources

# With optional filter
result = client.sources.list(
    filter_str="type:github",  # Optional filter
    page_size=10
)

for source in result['sources']:
    print(source.id)

List All Sources

all_sources = client.sources.list_all()
github_repos = [s for s in all_sources if s.github_repo]
print(f"Total GitHub sources: {len(github_repos)}")

Data Models

All API responses are returned as strongly-typed dataclasses:

Session

@dataclass
class Session:
    name: str
    id: str
    prompt: str
    source_context: SourceContext
    title: str
    state: SessionState  # Enum
    url: str
    create_time: str
    update_time: str
    outputs: List[SessionOutput]
    require_plan_approval: bool

SessionState Enum

class SessionState(str, Enum):
    STATE_UNSPECIFIED = "STATE_UNSPECIFIED"
    QUEUED = "QUEUED"
    PLANNING = "PLANNING"
    AWAITING_PLAN_APPROVAL = "AWAITING_PLAN_APPROVAL"
    AWAITING_USER_FEEDBACK = "AWAITING_USER_FEEDBACK"
    IN_PROGRESS = "IN_PROGRESS"
    PAUSED = "PAUSED"
    FAILED = "FAILED"
    COMPLETED = "COMPLETED"

Activity

@dataclass
class Activity:
    name: str
    id: str
    description: str
    create_time: str
    originator: str
    artifacts: List[Artifact]
    # One of these will be set:
    agent_messaged: Optional[Dict]
    user_messaged: Optional[Dict]
    plan_generated: Optional[Dict]
    plan_approved: Optional[Dict]
    progress_updated: Optional[Dict]
    session_completed: Optional[Dict]
    session_failed: Optional[Dict]

Source

@dataclass
class Source:
    name: str
    id: str
    github_repo: Optional[GitHubRepo]

Error Handling

The SDK provides specific exception types for different error cases:

from jules_agent_sdk.exceptions import (
    JulesAPIError,           # Base exception
    JulesAuthenticationError,  # 401 errors
    JulesNotFoundError,        # 404 errors
    JulesValidationError,      # 400 errors
    JulesRateLimitError,       # 429 errors
)

try:
    session = client.sessions.create(
        prompt="Task",
        source="sources/invalid"
    )
except JulesAuthenticationError:
    print("Invalid API key")
except JulesValidationError as e:
    print(f"Validation error: {e.message}")
except JulesAPIError as e:
    print(f"API error: {e.status_code} - {e.message}")

Advanced Examples

Monitor Session Progress

import time
from jules_agent_sdk import JulesClient
from jules_agent_sdk.models import SessionState

client = JulesClient(api_key="your-api-key")

# Create session
session = client.sessions.create(
    prompt="Implement new feature",
    source="sources/repo-id",
    starting_branch="main"
)

# Poll and display progress
while True:
    session = client.sessions.get(session.id)
    print(f"State: {session.state}")

    if session.state in [SessionState.COMPLETED, SessionState.FAILED]:
        break

    # Get latest activities
    activities = client.activities.list(session.id, page_size=5)
    for activity in activities['activities']:
        if activity.progress_updated:
            update = activity.progress_updated
            print(f"Progress: {update['title']} - {update['description']}")

    time.sleep(5)

Handle Plan Approval

from jules_agent_sdk import JulesClient
from jules_agent_sdk.models import SessionState

client = JulesClient(api_key="your-api-key")

session = client.sessions.create(
    prompt="Complex refactoring task",
    source="sources/repo-id",
    require_plan_approval=True  # Require manual approval
)

# Wait for plan to be generated
while True:
    session = client.sessions.get(session.id)

    if session.state == SessionState.AWAITING_PLAN_APPROVAL:
        # Get the plan from activities
        activities = client.activities.list_all(session.id)
        for activity in activities:
            if activity.plan_generated:
                plan = activity.plan_generated['plan']
                print("Generated Plan:")
                for step in plan['steps']:
                    print(f"  {step['index']}: {step['title']}")

                # Approve the plan
                client.sessions.approve_plan(session.id)
                print("Plan approved!")
                break
        break

    time.sleep(2)

Async Concurrent Operations

import asyncio
from jules_agent_sdk import AsyncJulesClient

async def create_and_monitor_session(client, prompt, source):
    """Create a session and return when complete."""
    session = await client.sessions.create(
        prompt=prompt,
        source=source,
        starting_branch="main"
    )
    completed = await client.sessions.wait_for_completion(session.id)
    return completed

async def main():
    async with AsyncJulesClient(api_key="your-api-key") as client:
        # Run multiple sessions concurrently
        tasks = [
            create_and_monitor_session(client, "Fix bug A", "sources/repo1"),
            create_and_monitor_session(client, "Fix bug B", "sources/repo2"),
            create_and_monitor_session(client, "Add feature C", "sources/repo3"),
        ]

        results = await asyncio.gather(*tasks)

        for i, session in enumerate(results):
            print(f"Session {i+1}: {session.state}")

asyncio.run(main())

Development

Running Tests

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run with coverage
pytest --cov=jules_agent_sdk --cov-report=html

Code Quality

# Format code
black src tests

# Type checking
mypy src

# Linting
flake8 src tests

License

MIT License - see LICENSE file for details.

Support

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jules_agent_sdk-0.1.1.tar.gz (29.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jules_agent_sdk-0.1.1-py3-none-any.whl (23.1 kB view details)

Uploaded Python 3

File details

Details for the file jules_agent_sdk-0.1.1.tar.gz.

File metadata

  • Download URL: jules_agent_sdk-0.1.1.tar.gz
  • Upload date:
  • Size: 29.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.6

File hashes

Hashes for jules_agent_sdk-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6b962ca94cf5e21715406868ec1106a5df204cf772df1287ac9d0f31ef8f2e30
MD5 44afe10441d08689abd2ea70513e6cfc
BLAKE2b-256 2bf035f5e684a815a11c59aae3c02c4f3f116f7aba97fa837cae0e7c588a7368

See more details on using hashes here.

File details

Details for the file jules_agent_sdk-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for jules_agent_sdk-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1234191d8e3fc6ba18812dbdcd5295e4960c25f553385f08d0561f29fca0aa55
MD5 cad66418775362ce53213fbd4f78bb0e
BLAKE2b-256 f3c529e780c4620ac4f7a2b21709aa3b4cb0d927a74f35fb2f1c947e0f6c11fa

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page