Metadata-Version: 2.4
Name: forgevault
Version: 0.1.2
Summary: ForgeVault SDK - Prompt management for production AI applications
Author-email: ForgeVault <forgevault.app@gmail.com>
Maintainer-email: ForgeVault <forgevault.app@gmail.com>
License: Proprietary
Project-URL: Homepage, https://forgevault.netlify.app
Keywords: llm,prompt,ai,openai,anthropic,prompt-engineering,prompt-management
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24.0
Provides-Extra: cli
Requires-Dist: typer>=0.9.0; extra == "cli"
Requires-Dist: rich>=13.0.0; extra == "cli"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: isort>=5.12.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: typer>=0.9.0; extra == "dev"
Requires-Dist: rich>=13.0.0; extra == "dev"
Dynamic: license-file

# ForgeVault Python SDK

Prompt management for production AI applications.

## Installation

```bash
# Core SDK
pip install forgevault

# With CLI support
pip install forgevault[cli]
```

## Quick Start

```python
from forgevault import Forge

# Initialize with your API key
forge = Forge(api_key="fv_your_api_key")

# Get a prompt by name
prompt = forge.get_prompt(prompt_name="customer-support-reply")

# Run with variables (model is required)
response = prompt.run(
    model="gpt-4o",
    customer_name="Sarah",
    issue="refund request"
)

print(response)
```

## CLI Usage

The SDK includes a command-line interface for managing prompts.

### Setup

```bash
# Login (one time) - prompts for API key securely
forgevault login

# Check status
forgevault whoami
```

### Commands

```bash
# List all prompts
forgevault list

# Get prompt details
forgevault get "My Prompt Name"
forgevault get "My Prompt Name" --full    # Show full content
forgevault get "My Prompt Name" --json    # JSON output

# Run a prompt
forgevault run "My Prompt Name" --model gpt-4o --var "input=hello world"
forgevault run "My Prompt Name" -m gpt-4o -V "name=John" -V "query=test"
forgevault run "My Prompt Name" --model gpt-4o --stream  # Stream output

# Render without executing (preview)
forgevault render "My Prompt Name" --var "input=test"

# View prompt version history
forgevault prompt-versions "My Prompt Name"

# Cache management
forgevault cache clear
forgevault cache stats

# Logout
forgevault logout
```

### Environment Variables

```bash
export FORGEVAULT_API_KEY=fv_your_api_key
```

## Features

- **Live Prompts**: Change prompts in ForgeVault UI, no redeploy needed
- **Version Control**: Pin to specific versions for stability
- **Streaming**: Real-time streaming support for LLM responses
- **Caching**: Built-in caching with configurable TTL
- **Fallback**: Offline fallback when API is unreachable
- **Async Support**: Full async/await support
- **CLI**: Command-line interface for testing and automation

## Configuration

```python
from forgevault import Forge

forge = Forge(
    api_key="fv_xxx",           # Required (or set FORGEVAULT_API_KEY, or use 'forgevault login')
    timeout=120,                # Request timeout in seconds (default: 120)
    cache_ttl=300,              # Cache TTL in seconds (default: 300)
    cache_enabled=True,         # Enable caching (default: True)
    fallback_enabled=True,      # Enable offline fallback (default: True)
)
```

## Usage

### Fetch by ID or Name

```python
# By name
prompt = forge.get_prompt(prompt_name="email-classifier")

# By ID
prompt = forge.get_prompt(prompt_id="507f1f77bcf86cd799439011")

# Specific version
prompt = forge.get_prompt(prompt_name="email-classifier", version="abc123")
```

### Run a Prompt

```python
# Using prompt object (model is required)
prompt = forge.get_prompt(prompt_name="my-prompt")
result = prompt.run(
    model="gpt-4o",
    email_content="I want a refund"
)

# With temperature and max_tokens
result = prompt.run(
    model="gpt-4o",
    email_content="I want a refund",
    temperature=0.7,
    max_tokens=500
)
```

### Run Directly (Without Getting Prompt First)

```python
# Run by prompt name
result = forge.run_prompt(
    model="gpt-4o",
    prompt_name="email-classifier",
    variables={"email_content": "I want a refund"}
)

# Run by prompt ID
result = forge.run_prompt(
    model="gpt-4o",
    prompt_id="507f1f77bcf86cd799439011",
    variables={"email_content": "I want a refund"}
)

# With version and overrides
result = forge.run_prompt(
    model="gpt-4o",
    prompt_name="email-classifier",
    variables={"email_content": "I want a refund"},
    version="abc123",
    temperature=0.5
)
```

### Render Without Executing

```python
# Get formatted messages (OpenAI format)
messages = prompt.render(email_content="I want a refund")
# Returns: {"messages": [{"role": "system", "content": "..."}, ...]}

# Or render directly
messages = forge.render_prompt(
    prompt_name="email-classifier",
    variables={"email_content": "I want a refund"}
)
```

### List All Prompts

```python
prompts = forge.list_prompts()
for p in prompts:
    print(f"{p['name']} - {p['version']}")
```

### Get Version History

```python
versions = forge.get_versions(prompt_name="my-prompt")
for v in versions:
    print(f"{v['version']}: {v['commit_message']}")
```

### Streaming

```python
# Stream response chunks as they arrive
for chunk in forge.run_prompt_stream(
    model="gpt-4o",
    prompt_name="my-prompt",
    variables={"input": "hello"}
):
    print(chunk, end="", flush=True)

# Async streaming
async for chunk in forge.run_prompt_stream_async(
    model="gpt-4o",
    prompt_name="my-prompt",
    variables={"input": "hello"}
):
    print(chunk, end="", flush=True)
```

### Async Usage

```python
import asyncio
from forgevault import Forge

async def main():
    forge = Forge(api_key="fv_xxx")
    
    prompt = await forge.get_prompt_async(prompt_name="my-prompt")
    result = await prompt.run_async(model="gpt-4o", name="John")
    
    print(result)
    await forge.aclose()

asyncio.run(main())
```

## Prompt Object

```python
prompt = forge.get_prompt(prompt_name="my-prompt")

# Metadata
print(prompt.id)           # Prompt ID
print(prompt.name)         # Prompt name
print(prompt.version)      # Current version (commit ID)
print(prompt.prompt_type)  # "System User", "User Only", etc.
print(prompt.variables)    # List of PromptVariable objects

# Content
print(prompt.system_prompt)
print(prompt.user_prompt)
print(prompt.few_shot_examples)

# Validate variables
missing = prompt.validate_variables({"name": "John"})
if missing:
    print(f"Missing: {missing}")
```

## Caching

```python
# Disable caching
forge = Forge(api_key="fv_xxx", cache_enabled=False)

# Custom TTL (10 minutes)
forge = Forge(api_key="fv_xxx", cache_ttl=600)

# Invalidate cache
forge.invalidate_cache("my-prompt")  # Specific prompt
forge.invalidate_cache()              # All prompts

# Check cache stats
stats = forge.cache_stats()
print(stats)  # {"total_entries": 5, "valid_entries": 4, ...}
```

## Error Handling

```python
from forgevault import (
    Forge,
    ForgeVaultError,
    AuthenticationError,
    PromptNotFoundError,
    ExecutionError,
    RateLimitError
)

try:
    prompt = forge.get_prompt(prompt_name="nonexistent")
except PromptNotFoundError as e:
    print(f"Prompt not found: {e}")
except AuthenticationError as e:
    print(f"Auth failed: {e}")
except RateLimitError as e:
    print(f"Rate limited. Retry after: {e.details['retry_after']}s")
except ForgeVaultError as e:
    print(f"Error [{e.error_code}]: {e.message}")
```

## Best Practices

### 1. Use Environment Variables

```python
# Don't hardcode API keys
forge = Forge()  # Uses FORGEVAULT_API_KEY env var
```

### 2. Pin Versions in Production

```python
# Development: use latest
prompt = forge.get_prompt(prompt_name="my-prompt")

# Production: pin to specific version
prompt = forge.get_prompt(prompt_name="my-prompt", version="abc123def456")
```

### 3. Handle Failures Gracefully

```python
from forgevault.exceptions import ConnectionError

try:
    prompt = forge.get_prompt(prompt_name="my-prompt")
except ConnectionError:
    # Fallback will be used automatically if enabled
    # Or handle manually
    prompt = get_hardcoded_fallback()
```

### 4. Use Context Manager

```python
with Forge(api_key="fv_xxx") as forge:
    prompt = forge.get_prompt(prompt_name="my-prompt")
    result = prompt.run(model="gpt-4o", name="John")
# Connections automatically closed
```

## License

Copyright (c) 2025 ForgeVault. All Rights Reserved.

This is proprietary software. See LICENSE file for terms.
