Skip to main content

FACL - Python SDK for Frappe Assistant Cloud

A Python SDK for integrating with Frappe Assistant Cloud (FACL) - the AI-powered assistant backend for the Frappe ecosystem.

Features

  • Sync and Async Clients - Choose between FACLClient (requests) or AsyncFACLClient (aiohttp)
  • SSE Streaming - Real-time streaming responses with tool execution
  • HMAC Authentication - Secure request signing
  • Auto Model Selection - Intelligent model routing with cross-provider fallback
  • Full API Coverage - Chat, billing, conversations, user management, and more
  • Type Hints - Full type annotations for better IDE support

Installation

# Basic installation (sync client only)
pip install facl

# With async support
pip install facl[async]

# Development installation
pip install facl[dev]

# Everything
pip install facl[all]

Quick Start

Sync Client

from facl import FACLClient

client = FACLClient(
    tenant_id="your-tenant-id",
    tenant_secret="your-secret",
    facl_url="https://facl.frappe.cloud"
)

# List available models
models = client.list_available_models()
for model in models.get("models", []):
    print(f"{model['model_id']} - {model['display_name']}")

# Stream a chat response
for event in client.stream_chat(
    session_id="session-123",
    message="What can you help me with?",
    user_id="user@example.com",
    model_id="auto"  # Use auto-model selection
):
    if event["event"] == "stream_chunk":
        print(event["data"].get("content", ""), end="", flush=True)
    elif event["event"] == "stream_complete":
        print(f"\n\nTokens used: {event['data'].get('tokens_used')}")

Async Client

import asyncio
from facl import AsyncFACLClient

async def main():
    async with AsyncFACLClient(
        tenant_id="your-tenant-id",
        tenant_secret="your-secret"
    ) as client:
        async for event in client.stream_chat(
            session_id="session-123",
            message="Hello!",
            user_id="user@example.com"
        ):
            if event["event"] == "stream_chunk":
                print(event["data"].get("content", ""), end="")

asyncio.run(main())

Custom Logger

import logging
from facl import FACLClient

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("my_app.facl")

client = FACLClient(
    tenant_id="your-tenant-id",
    tenant_secret="your-secret",
    logger=logger
)

SSE Event Types

When streaming, you'll receive events with these types:

Event Description
stream_start Stream initialized
stream_chunk Text chunk from LLM
stream_complete Full response with metrics
stream_error Error occurred
thinking Reasoning/thinking content
tool_call_start Tool execution beginning
tool_call_result Tool execution complete
approval_required HITL approval needed
tool_cancelled Tool was rejected
model_fallback Auto mode selected a model
rate_limited All models rate limited

API Reference

FACLClient / AsyncFACLClient

Chat & Streaming

  • stream_chat(session_id, message, user_id, context=None, model_id=None) - Stream chat response

Models

  • list_available_models() - List available AI models
  • set_preferred_model(model_id) - Set preferred model

Tenant

  • get_tenant_info() - Get tenant information
  • accept_terms(terms_version, accepted_by) - Accept terms and conditions

Conversations

  • list_conversations(user_id=None, limit=50, offset=0) - List conversations
  • get_conversation(conversation_id) - Get conversation details
  • get_messages(conversation_id, limit=100, offset=0) - Get messages
  • create_message(conversation_id, message_id, role, content, ...) - Create message
  • update_conversation(conversation_id, title=None, user_id=None) - Update conversation
  • delete_conversation(conversation_id) - Soft delete conversation
  • delete_message(conversation_id, message_id) - Soft delete message

Billing

  • get_plan_comparison() - Get available plans
  • get_usage_dashboard() - Get usage statistics
  • get_usage_history(days=30) - Get historical usage
  • initiate_checkout(plan, billing_cycle="monthly") - Start checkout
  • verify_checkout(session_id=None) - Verify payment
  • upgrade_plan(new_plan, billing_cycle="monthly") - Upgrade subscription
  • cancel_subscription(cancel_immediately=False) - Cancel subscription

Users & MCP Servers

  • register_user(user_id, display_name=None, custom_instructions=None) - Register user
  • get_user(user_id) - Get user details
  • get_user_auth_status(user_id) - Check auth status
  • add_user_mcp_server(user_id, server_name, endpoint_url, ...) - Add MCP server
  • get_user_mcp_servers(user_id) - List user's MCP servers
  • update_mcp_server_tokens(user_id, server_name, access_token, ...) - Update tokens
  • remove_user_mcp_server(user_id, server_name) - Remove MCP server

Prompts

  • list_prompts(user_id, cursor=None) - List prompt templates
  • get_prompt(prompt_name, arguments=None, user_id=None) - Get rendered prompt

Tools

  • list_tools(user_id, server=None) - List MCP tools with input schemas

Standalone Functions

from facl import get_terms, register_tenant

# Get current terms (no auth required)
terms = get_terms("https://facl.frappe.cloud")

# Register a new tenant
result = register_tenant(
    facl_url="https://facl.frappe.cloud",
    site_url="https://mysite.frappe.cloud",
    terms_accepted=True,
    terms_version="1.0",
    accepted_by="admin@example.com"
)

Exceptions

from facl.exceptions import (
    FACLError,              # Base exception
    FACLAuthenticationError, # HMAC signature failed
    FACLRateLimitError,     # Rate limit exceeded (has retry_after)
    FACLStreamError,        # SSE streaming error
    FACLConfigurationError, # Invalid configuration
)

Frappe Integration

For Frappe applications, create a thin adapter:

import frappe
from facl import FACLClient

class FrappeLogger:
    def error(self, msg, *args, **kwargs):
        frappe.log_error(msg, kwargs.get('category', 'FACL'))

def get_facl_client():
    settings = frappe.get_single("FACO Settings")
    if settings.registration_status != "Registered":
        return None

    return FACLClient(
        tenant_id=settings.tenant_id,
        tenant_secret=settings.get_password("tenant_secret"),
        facl_url=settings.facl_url,
        logger=FrappeLogger()
    )

License

GNU Affero General Public License v3.0

Copyright (C) 2025 Paul Clinton

Download files

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

Source Distribution

assistant_runtime_sdk-1.0.0.tar.gz (65.0 kB view details)

Uploaded Source

Built Distribution

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

assistant_runtime_sdk-1.0.0-py3-none-any.whl (67.1 kB view details)

Uploaded Python 3

File details

Details for the file assistant_runtime_sdk-1.0.0.tar.gz.

File metadata

  • Download URL: assistant_runtime_sdk-1.0.0.tar.gz
  • Upload date:
  • Size: 65.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.3

File hashes

Hashes for assistant_runtime_sdk-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3d3f707ab89711ce3e573cc58ddd51a6b15fe4aad432774f52161e80be7a1a78
MD5 b5bbb79be79e012649ebfebaed0acd6e
BLAKE2b-256 34ebdb8093797650dd6e5fd715c2bc47d5830f562ff6253ef62f55e69aea4b2b

See more details on using hashes here.

File details

Details for the file assistant_runtime_sdk-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for assistant_runtime_sdk-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 56409dc139f31e0167ae8cc13cc46e25aebc396b4703e484be73fde1894b47d5
MD5 e0f6d8e9e1c449ca9c1bd7c175926f8d
BLAKE2b-256 a53c910bdcdbdbf64f7a7e822db5686b600b52d454ce76532d72f94cf514ea71

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 Sentry Error logging StatusPage Status page