usf-agents


Nameusf-agents JSON
Version 2.2.0 PyPI version JSON
download
home_pageNone
SummaryA lightweight multi-agent orchestration framework with better control, easy to use for complex to simple use cases. Developer friendly with more visibility and supports all models with OpenAI compatible API.
upload_time2025-08-29 05:48:42
maintainerNone
docs_urlNone
authorUltraSafe AI Team
requires_python>=3.8
licenseUSF Agents SDK License
keywords multi-agent orchestration framework lightweight agent developer-friendly visibility control complex-usecase simple-usecase all-models openai-compatible llm ai-agent tool-calling streaming usf planning ultrasafe ultrasafe ai usf-agents
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # USF Agent SDK

A flexible, OpenAI-compatible Agent SDK that provides intelligent planning and tool execution capabilities using the official USF Agent SDK APIs.

## 🚀 Features

- **Multi-Stage Configuration** - Different models for planning, tool calling, and final responses
- **Manual Tool Execution** - Complete user control over tool implementations
- **Provider Flexibility** - Mix different LLM providers (USF, OpenAI, Anthropic, etc.)
- **Memory Management** - Built-in conversation memory with auto-trimming
- **Streaming Support** - Real-time response streaming
- **Automatic Date/Time Appending** - All final responses include current UTC timestamp
- **Date/Time Override** - Custom date, time, and timezone configuration support
- **Extra Parameters Support** - Pass any OpenAI API parameters for advanced control
- **Type Hints Support** - Full type annotations included

## 📦 Installation

```bash
pip install usf-agents
```

## 🎯 Quick Start

```python
from usf_agents import USFAgent

# Basic configuration
agent = USFAgent({
    'api_key': 'your-usf-api-key',
    'model': 'usf-mini'
})

# Simple query without tools
async for result in agent.run('Hello, how are you?'):
    if result['type'] == 'final_answer':
        print('Response:', result['content'])
```

## 🔄 Core Workflow

The USF Agent follows a three-stage workflow:

```
User Request → Plan → Tool/Agent Call → Tool/Agent Execution → Plan → ... → Plan → Final Response
```

1. **Planning Stage** - Agent analyzes the request and decides if tools are needed
2. **Tool Calling Stage** - Agent generates tool calls in OpenAI format (if needed)
3. **Final Response Stage** - Agent generates the final user-facing response


## ⚙️ Configuration

### Basic Configuration

```python
agent = USFAgent({
    'api_key': 'your-api-key',                    # Required
    'base_url': 'https://api.us.inc/usf/v1',      # Default USF endpoint
    'model': 'usf-mini',                          # Default model
    'introduction': 'You are a helpful AI',       # Custom system prompt
    'knowledge_cutoff': '15 January 2025',        # Knowledge cutoff date
    'stream': False,                              # Enable streaming
    'max_loops': 20,                              # Maximum planning/tool loops (default: 20)
    
    # User context (applies to all stages)
    'backstory': 'I am a software engineer working on improving user experience.',
    'goal': 'Create intuitive and efficient solutions for users.',
    
    # Memory configuration
    'temp_memory': {
        'enabled': True,
        'max_length': 10,
        'auto_trim': True
    }
})
```

## 👤 User Context: Backstory and Goal

The USF Agent SDK supports user context through `backstory` and `goal` parameters that provide personality and objective guidance to enhance agent interactions.

### Basic Usage

```python
agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a software engineer working on improving user experience for our application.',
    'goal': 'Create intuitive and efficient solutions that help users accomplish their tasks quickly.'
})
```

### How It Works

- **Planning & Tool Calling**: Backstory and goal are passed directly as API parameters to `usf-agent/plan` and `usf-agent/tool-call` endpoints
- **Final Response**: When generating the final response, backstory and goal are added to the system message to provide context
- **Consistency**: The same backstory and goal apply to all stages of the agent workflow
- **Memory**: Backstory and goal context is maintained throughout the conversation

### Advanced Examples

```python
# Customer service agent
customer_service_agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a customer service representative with 5 years of experience helping customers resolve technical issues.',
    'goal': 'Provide helpful, empathetic, and efficient support to resolve customer problems quickly.',
    'model': 'usf-mini'
})

# Research assistant
research_agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a research scientist with expertise in data analysis and academic writing.',
    'goal': 'Provide accurate, well-sourced information and help users understand complex topics.',
    'final_response': {
        'temperature': 0.3  # More factual responses
    }
})

# Creative writing assistant
creative_agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a creative writer and storyteller with a passion for engaging narratives.',
    'goal': 'Help users craft compelling stories and improve their writing skills.',
    'final_response': {
        'temperature': 0.8,  # More creative responses
        'presence_penalty': 0.2
    }
})
```

### Context Enhancement using backstory and goal

When backstory and goal are provided, they automatically enhance the agent's understanding and response quality. The agent uses this context to provide more personalized and relevant responses.

```python
# Example 1: Technical support context
support_agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a product manager at a tech startup focusing on mobile applications.',
    'goal': 'Improve user engagement and retention through better UX design.'
})

# Example 2: Development context
technical_agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a senior developer debugging performance issues in our microservices architecture.',
    'goal': 'Identify bottlenecks and optimize system performance to handle 10x more traffic.'
})

# Example 3: Marketing context
content_agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a marketing manager creating content for our B2B SaaS platform.',
    'goal': 'Generate compelling content that converts prospects into customers.'
})

# The agent will use this context throughout the conversation
async for result in support_agent.run('How can I improve our app\'s user onboarding?'):
    if result['type'] == 'final_answer':
        print(result['content'])
        break

async for result in technical_agent.run('Our API response times are slow, what should I investigate?'):
    if result['type'] == 'final_answer':
        print(result['content'])
        break

async for result in content_agent.run('Write a blog post about our new feature.'):
    if result['type'] == 'final_answer':
        print(result['content'])
        break
```

### Best Practices

```python
# ✅ Good: Specific and relevant backstory
agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am a frontend developer working on a React application for e-commerce.',
    'goal': 'Build responsive, accessible components that improve user conversion rates.'
})

# ❌ Avoid: Vague or irrelevant context
agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I like computers.',
    'goal': 'Do stuff.'
})

# ✅ Good: Task-specific context
debugging_agent = USFAgent({
    'api_key': 'your-api-key',
    'backstory': 'I am debugging a Python application that handles user authentication.',
    'goal': 'Identify and fix the root cause of authentication failures in production.'
})
```

### Multi-Stage Configuration

Use different models for each stage to optimize cost and performance:

```python
agent = USFAgent({
    # Default fallback configuration
    'api_key': 'default-key',
    'base_url': 'https://api.us.inc/usf/v1',
    'model': 'usf-mini',
    
    # Planning stage - Use powerful model for complex reasoning
    'planning': {
        'api_key': 'planning-key',
        'model': 'usf-mini',
        'introduction': 'You are an expert planning assistant.'
    },
    
    # Tool calling stage - Use fast model for efficiency
    'tool_calling': {
        'api_key': 'tool-key',
        'model': 'usf-mini-x1'
    },
    
    # Final response stage - Use different provider
    'final_response': {
        'api_key': 'api-key',
        'base_url': 'https://api.us.inc/usf/v1',
        'model': 'usf-mini',
        'temperature': 0.7
    }
})
```

## 🕒 Automatic Date/Time Feature

The USF Agent SDK automatically appends the current date and time to all final responses. This feature:

- **Always Active** - No configuration required, works automatically
- **UTC Timezone** - Consistent timezone for all responses
- **Format**: `Current date: MM/DD/YYYY, HH:MM:SS AM/PM (UTC Timezone).`
- **Universal Coverage** - Works with both streaming and non-streaming modes
- **All Response Paths** - Applies to both OpenAI-based and legacy response generation

### Example Output

```python
# User query: "What is the capital of France?"
# Agent response will end with:
"Current system time is 5:54 AM (UTC)."
```

### Technical Details

The date/time is automatically injected during the message processing phase, ensuring that:
- The LLM receives instructions to include the timestamp
- The timestamp reflects the exact moment of response generation
- No additional API calls or processing overhead
- Consistent format across all responses

### Date/Time Override

You can override the default UTC timestamp with custom date, time, and timezone:

#### Static Date/Time Override

```python
# Global configuration with static override
agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        'date_time_override': {
            'enabled': True,
            'date': '12/25/2025',        # MM/DD/YYYY format required
            'time': '11:30:45 PM',       # HH:MM:SS AM/PM format required
            'timezone': 'EST'            # Any timezone string
        }
    }
})

# Per-request override
async for result in agent.run('What time is it?', {
    'date_time_override': {
        'enabled': True,
        'date': '01/01/2026',
        'time': '12:00:00 AM',
        'timezone': 'UTC'
    }
}):
    if result['type'] == 'final_answer':
        response = result['content']
        break
```

#### Dynamic/Real-time Date/Time Override

```python
import datetime
from zoneinfo import ZoneInfo

# Function to get current time in specific timezone
def get_current_time_in_timezone(timezone):
    now = datetime.datetime.now(ZoneInfo(timezone))
    
    return {
        'date': now.strftime('%m/%d/%Y'),
        'time': now.strftime('%I:%M:%S %p'),
        'timezone': timezone
    }

# Dynamic override for different timezones
tokyo_time = get_current_time_in_timezone('Asia/Tokyo')
async for result in agent.run('What time is it in Tokyo?', {
    'date_time_override': {
        'enabled': True,
        **tokyo_time
    }
}):
    if result['type'] == 'final_answer':
        response = result['content']
        break

# Multiple timezone examples
timezones = [
    'America/New_York',
    'Europe/London', 
    'Asia/Tokyo',
    'Australia/Sydney',
    'America/Los_Angeles'
]

for tz in timezones:
    time_data = get_current_time_in_timezone(tz)
    async for result in agent.run(f'What\'s happening now in {tz}?', {
        'date_time_override': {
            'enabled': True,
            **time_data
        }
    }):
        if result['type'] == 'final_answer':
            response = result['content']
            break
```

#### Timezone Format Examples

```python
# Various supported timezone formats
timezone_examples = [
    # Standard abbreviations
    {'timezone': 'EST', 'description': 'Eastern Standard Time'},
    {'timezone': 'PST', 'description': 'Pacific Standard Time'},
    {'timezone': 'GMT', 'description': 'Greenwich Mean Time'},
    
    # Full timezone names
    {'timezone': 'Eastern Standard Time', 'description': 'Full name'},
    {'timezone': 'Pacific Standard Time', 'description': 'Full name'},
    
    # UTC offsets
    {'timezone': 'UTC-5', 'description': 'UTC offset negative'},
    {'timezone': 'UTC+9', 'description': 'UTC offset positive'},
    
    # IANA timezone identifiers (recommended)
    {'timezone': 'America/New_York', 'description': 'IANA identifier'},
    {'timezone': 'Europe/London', 'description': 'IANA identifier'},
    {'timezone': 'Asia/Tokyo', 'description': 'IANA identifier'},
    {'timezone': 'Australia/Sydney', 'description': 'IANA identifier'}
]
```

#### Validation and Fallback

```python
# Invalid formats automatically fallback to UTC
invalid_examples = [
    {
        'enabled': True,
        'date': '2025-12-25',      # Wrong format (YYYY-MM-DD)
        'time': '23:30:45',        # Wrong format (24-hour)
        'timezone': 'EST'
    },
    {
        'enabled': True,
        'date': '12/25/2025',
        'time': '11:30:45 PM'
        # Missing timezone
    },
    {
        'enabled': False,           # Disabled override
        'date': '12/25/2025',
        'time': '11:30:45 PM',
        'timezone': 'EST'
    }
]

# All above examples will fallback to UTC automatically
```

## 🔧 Extra Parameters Support

The USF Agent SDK supports passing any additional OpenAI API parameters directly to the final response generation. This provides full access to OpenAI's chat completion capabilities.

### Basic Extra Parameters

```python
# Global configuration with extra parameters
agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        # Standard parameters
        'temperature': 0.7,
        'stop': ['END'],
        
        # Extra OpenAI parameters
        'max_tokens': 1000,
        'top_p': 0.9,
        'presence_penalty': 0.1,
        'frequency_penalty': 0.2,
        'seed': 12345,
        'user': 'user-123'
    }
})
```

### Structured Output with JSON Schema

```python
# Complex response_format with JSON schema
structured_agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        'response_format': {
            'type': 'json_schema',
            'json_schema': {
                'name': 'book_info',
                'strict': True,
                'schema': {
                    'type': 'object',
                    'properties': {
                        'title': {
                            'type': 'string',
                            'description': 'Title of the book'
                        },
                        'author': {
                            'type': 'string', 
                            'description': 'Author of the book'
                        },
                        'year_published': {
                            'type': 'number',
                            'description': 'Year the book was first published'
                        },
                        'genre': {
                            'type': 'string',
                            'enum': ['fiction', 'non-fiction', 'mystery', 'romance', 'sci-fi'],
                            'description': 'Genre of the book'
                        },
                        'rating': {
                            'type': 'number',
                            'minimum': 1,
                            'maximum': 5,
                            'description': 'Rating out of 5 stars'
                        }
                    },
                    'required': ['title', 'author', 'year_published'],
                    'additionalProperties': False
                }
            }
        },
        'temperature': 0.1  # Low temperature for consistent JSON
    }
})

# This will force structured JSON output
async for result in structured_agent.run('Tell me about the book "1984"'):
    if result['type'] == 'final_answer':
        book_info = result['content']
        break
```

### Advanced Parameter Examples

```python
# Token control with logit_bias
biased_agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        'logit_bias': {
            '1820': 10,     # Boost 'positive' token
            '4633': -10,    # Reduce 'negative' token  
            '50256': -100   # Avoid end-of-text token
        },
        'temperature': 0.8
    }
})

# Deterministic responses with seed
deterministic_agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        'seed': 42,
        'temperature': 0.7  # Same seed + temp = consistent results
    }
})

# Creative writing with penalties
creative_agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        'presence_penalty': 0.6,   # Encourage new topics
        'frequency_penalty': 0.3,  # Reduce repetition
        'temperature': 0.9,        # High creativity
        'max_tokens': 500
    }
})

# Streaming with usage tracking
streaming_agent = USFAgent({
    'api_key': 'your-api-key',
    'stream': True,
    'final_response': {
        'stream_options': {
            'include_usage': True
        },
        'max_tokens': 200
    }
})
```

### Per-Request Parameter Override

```python
# Mix global and per-request parameters
flexible_agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        'temperature': 0.7,  # Global default
        'max_tokens': 500    # Global default
    }
})

# Request 1: JSON output
async for result in flexible_agent.run('List 3 colors', {
    'final_response': {
        'response_format': {'type': 'json_object'},
        'temperature': 0.1,  # Override global
        'max_tokens': 100    # Override global
    }
}):
    if result['type'] == 'final_answer':
        json_response = result['content']
        break

# Request 2: Creative writing
async for result in flexible_agent.run('Write a short story', {
    'final_response': {
        'temperature': 0.9,      # Override global
        'presence_penalty': 0.4, # Add new parameter
        'max_tokens': 800,       # Override global
        'stop': ['THE END']      # Add stop sequence
    }
}):
    if result['type'] == 'final_answer':
        story_response = result['content']
        break

# Request 3: Deterministic output
async for result in flexible_agent.run('What is 2+2?', {
    'final_response': {
        'seed': 123,
        'temperature': 0.0,  # Most deterministic
        'max_tokens': 50
    }
}):
    if result['type'] == 'final_answer':
        fact_response = result['content']
        break
```

### Combining Date/Time Override with Extra Parameters

```python
# Use both features together
combined_agent = USFAgent({
    'api_key': 'your-api-key',
    'final_response': {
        # Date/time override
        'date_time_override': {
            'enabled': True,
            'date': '12/31/2025',
            'time': '11:59:59 PM',
            'timezone': 'EST'
        },
        
        # Extra OpenAI parameters
        'response_format': {
            'type': 'json_schema',
            'json_schema': {
                'name': 'year_end_summary',
                'schema': {
                    'type': 'object',
                    'properties': {
                        'year': {'type': 'number'},
                        'summary': {'type': 'string'},
                        'predictions': {
                            'type': 'array',
                            'items': {'type': 'string'}
                        }
                    },
                    'required': ['year', 'summary']
                }
            }
        },
        'max_tokens': 800,
        'temperature': 0.5
    }
})
```

### Supported Extra Parameters

| Parameter | Type | Description | Example |
|-----------|------|-------------|---------|
| `response_format` | dict | Control output format | `{'type': "json_object"}` |
| `max_tokens` | int | Maximum response length | `1000` |
| `top_p` | float | Nucleus sampling (0-1) | `0.9` |
| `presence_penalty` | float | New topic penalty (-2 to 2) | `0.1` |
| `frequency_penalty` | float | Repetition penalty (-2 to 2) | `0.2` |
| `logit_bias` | dict | Token probability control | `{"50256": -100}` |
| `seed` | int | Deterministic output | `12345` |
| `user` | str | User identifier | `"user-123"` |
| `stream_options` | dict | Streaming configuration | `{'include_usage': True}` |

### Important Notes

- **Scope**: Extra parameters only apply to final response generation
- **Validation**: Parameter validation is handled by the OpenAI API
- **Errors**: Invalid parameters will cause API errors (passed through directly)
- **Future-Proof**: Any new OpenAI parameters are automatically supported
- **Planning/Tools**: Extra parameters are ignored by planning and tool calling APIs

## 🧠 Advanced Multi-Agent Orchestration

The SDK now includes a flexible multi-agent orchestration layer on top of `USFAgent` that supports:
- Manager/SubAgent composition with agent-as-tool delegation
- Strict isolation (sub-agent tools/memory are never exposed)
- 4 context transfer modes:
  - NONE: do not pass caller messages
  - AGENT_DECIDED: pass full context only if the caller supplied it
  - ALWAYS_FULL: pass complete parent messages in OpenAI format
  - CONTEXT_PARAM: pass only an explicit lightweight context object
- Graph workflows (LangGraph-style) with nodes (agents/tools) and conditional edges
- Full trace recording and pre/post-execution visualization (Mermaid/Graphviz/JSON)

Public API quick import:
```python
from usf_agents import (
  USFAgent,
  # Multi-agent
  SubAgent, ManagerAgent, AgentRegistry,
  WorkflowGraph, ExecutionEngine,
  TraceRecorder, TraceStore,
  to_mermaid, to_graphviz, trace_to_json
)
```

### Example A: SubAgent delegation with isolation

```python
import asyncio
from usf_agents import SubAgent, ManagerAgent

# Create isolated sub-agents
math_agent = SubAgent({
    'id': 'math',
    'name': 'Math Specialist',
    'agent_type': 'sub',
    'context_mode': 'NONE',   # default: do not pass parent transcript
    'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}
})

code_agent = SubAgent({
    'id': 'coder',
    'name': 'Code Assistant',
    'agent_type': 'sub',
    'context_mode': 'CONTEXT_PARAM',  # pass only lightweight context objects
    'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}
})

# Manager agent
manager = ManagerAgent({
    'id': 'mgr',
    'name': 'Manager',
    'agent_type': 'manager',
    'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}
})

# Register sub-agents as callable tools for the manager
manager.add_sub_agent(math_agent, {
  'description': 'Delegate math tasks',
  'parameters': {
    'type': 'object',
    'properties': {
      'task': {'type': 'string'},
      'input': {'type': 'object'},
      'context_param': {'type': 'object'}
    },
    'required': ['task']
  }
}, alias='math_tool')

manager.add_sub_agent(code_agent, {
  'description': 'Delegate coding tasks',
  'parameters': {
    'type': 'object',
    'properties': {
      'task': {'type': 'string'},
      'input': {'type': 'object'},
      'context_param': {'type': 'object'}
    },
    'required': ['task']
  }
}, alias='coder_tool')

async def main():
    # Delegation with sub-agent policy NONE (no parent transcript)
    math_res = await manager.delegate(
        sub_id='math',
        task={'task': 'calculate', 'input': {'expression': '25 * 4'}}
    )
    print('Math result:', math_res)

    # Delegation with lightweight explicit context
    code_res = await manager.delegate(
        sub_id='coder',
        task={'task': 'generate_function', 'input': {'language': 'python', 'spec': 'sum(a,b)'}},
        policy='CONTEXT_PARAM',
        context_param={'style': 'concise'}
    )
    print('Code result:', code_res)

asyncio.run(main())
```

### Example B: 4 Context Modes

- NONE → Only the new task is passed to sub-agent.
- AGENT_DECIDED → Behaves like ALWAYS_FULL if caller messages are present, else NONE.
- ALWAYS_FULL → Pass full caller transcript + delegated task.
- CONTEXT_PARAM → Pass only a small explicit context object + delegated task.

Override per call:
```python
await manager.delegate(sub_id='math', task={...}, policy='ALWAYS_FULL', context_param=None)
```

### Example C: Graph workflow with conditional edges

```python
import asyncio
from usf_agents import SubAgent, AgentRegistry, WorkflowGraph, ExecutionEngine, TraceRecorder, to_mermaid

a = SubAgent({'id': 'A','name': 'Agent A','agent_type': 'sub','context_mode': 'NONE','usf_config': {'api_key': 'YOUR_API_KEY','model': 'usf-mini'}})
b = SubAgent({'id': 'B','name': 'Agent B','agent_type': 'sub','context_mode': 'CONTEXT_PARAM','usf_config': {'api_key': 'YOUR_API_KEY','model': 'usf-mini'}})

reg = AgentRegistry()
reg.add_agent(a)
reg.add_agent(b)

spec = {
  'nodes': [
    {'id': 'nodeA', 'type': 'agent', 'ref': 'A'},
    {'id': 'nodeB', 'type': 'agent', 'ref': 'B'}
  ],
  'edges': [
    {'source': 'nodeA', 'target': 'nodeB', 'condition': 'last.success == true'}
  ]
}
graph = WorkflowGraph(spec)
recorder = TraceRecorder()
engine = ExecutionEngine(graph, reg, recorder)

async def run():
    inputs = {
      'nodeA': {'task': 'greet', 'input': {'name': 'Alice'}},
      'nodeB': {'task': 'followup', 'input': {'topic': 'status'}}
    }
    outputs = await engine.run(entry_nodes=['nodeA'], inputs=inputs, max_steps=20)
    print('Outputs:', outputs)
    print('Mermaid:\n', to_mermaid(spec, recorder.snapshot()))

asyncio.run(run())
```

### Example D: Trace and visualization

```python
from usf_agents import TraceRecorder, to_mermaid, to_graphviz, trace_to_json
# Use TraceRecorder during workflow execution; then render:
diagram = to_mermaid(graph_spec, trace)  # Flowchart with [visited] annotations
dot = to_graphviz(graph_spec, trace)     # DOT format for Graphviz
print(trace_to_json(trace))              # Pretty JSON for logs
```

### Example E: Agent-as-tool adapter (classic tool_call path)

```python
import asyncio, json
from usf_agents import SubAgent
from usf_agents.multi_agent import make_agent_tool, handle_agent_tool_call

sub = SubAgent({
  'id': 'worker',
  'name': 'Worker',
  'agent_type': 'sub',
  'context_mode': 'AGENT_DECIDED',
  'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}
})

tool_def = make_agent_tool(sub, {'description': 'Invoke worker sub-agent'})
tool_call = {
  'id': 'call_1',
  'type': 'function',
  'function': {'name': tool_def['function']['name'], 'arguments': json.dumps({'task': 'do_work','input': {'x': 1}})}
}

async def run():
    res = await handle_agent_tool_call(sub, tool_call, calling_context=None, mode='AGENT_DECIDED')
    print(res)

asyncio.run(run())
```

For more recipes, see `usf_agents/examples/multi_agent_examples.md`.

## 📚 Usage Examples

### Example 1: Simple Query (No Tools)

```python
from usf_agents import USFAgent

agent = USFAgent({
    'api_key': 'your-api-key'
})

async for result in agent.run('What is 2 + 2?'):
    print(f"{result['type']}:", result.get('content') or result.get('plan'))
```

### Example 2: Weather Query with Tool Execution

```python
# Define your tools
tools = [
    {
        'type': 'function',
        'function': {
            'name': 'get_weather',
            'description': 'Get current weather for a location',
            'parameters': {
                'type': 'object',
                'properties': {
                    'location': {'type': 'string', 'description': 'City name'}
                },
                'required': ['location']
            }
        }
    }
]

# Custom tool execution function
async def execute_weather_tool(tool_call):
    name = tool_call['function']['name']
    args = json.loads(tool_call['function']['arguments'])
    
    # Your custom weather API logic here
    weather_data = await get_weather_from_api(args['location'])
    
    return {
        'role': 'tool',
        'tool_call_id': tool_call['id'],
        'name': name,
        'content': json.dumps(weather_data)
    }

# Main execution - Continue until agent provides final answer
messages = [
    {'role': 'user', 'content': 'What\'s the weather in New York?'}
]

while True:
    final_answer_received = False
    
    async for result in agent.run(messages, {'tools': tools}):
        if result['type'] == 'plan':
            print('Plan:', result['plan'])
            
            # Add plan to messages
            messages.append({
                'role': 'assistant',
                'content': result['content'],
                'type': 'agent_plan'
            })
        
        if result['type'] == 'tool_calls':
            print('Tools to execute:', result['tool_calls'])
            
            # Add tool call message
            messages.append({
                'role': 'assistant',
                'content': '',
                'tool_calls': result['tool_calls']
            })
            
            # Execute tools manually
            for tool_call in result['tool_calls']:
                tool_result = await execute_weather_tool(tool_call)
                messages.append(tool_result)
            
            # Break to continue the planning loop with tool results
            break
        
        if result['type'] == 'final_answer':
            print('Final Answer:', result['content'])
            final_answer_received = True
            break
    
    # Exit if we received the final answer
    if final_answer_received:
        break
```

### Example 3: Cost Optimization Setup

```python
cost_optimized_agent = USFAgent({
    # Use expensive model only for planning
    'planning': {
        'api_key': 'usf-key',
        'model': 'usf-mini'  # High-quality planning
    },
    
    # Use cheap model for tool calling
    'tool_calling': {
        'api_key': 'usf-key',
        'model': 'usf-mini-x1'  # Better tool calling
    },
    
    # Use mid-tier model for responses
    'final_response': {
        'api_key': 'usf-key',
        'model': 'usf-mini'  # Fast and high quality responses
    }
})
```

### Example 4: Provider Mixing

```python
mixed_provider_agent = USFAgent({
    # USF for planning and tool calling
    'planning': {
        'api_key': 'usf-key',
        'base_url': 'https://api.us.inc/usf/v1',
        'model': 'usf-mini'
    },
    
    'tool_calling': {
        'api_key': 'usf-key',
        'base_url': 'https://api.us.inc/usf/v1',
        'model': 'usf-mini-x1'
    },
    
    # OpenAI for final responses
    'final_response': {
        'api_key': 'openai-key',
        'base_url': 'https://api.openai.com/v1',
        'model': 'gpt-4'
    }
})
```

### Example 5: Custom Tool Implementation

```python
import json

# Multi-tool example
tools = [
    {
        'type': 'function',
        'function': {
            'name': 'calculator',
            'description': 'Perform mathematical calculations',
            'parameters': {
                'type': 'object',
                'properties': {
                    'expression': {'type': 'string', 'description': 'Math expression to evaluate'}
                },
                'required': ['expression']
            }
        }
    },
    {
        'type': 'function',
        'function': {
            'name': 'web_search',
            'description': 'Search the web for information',
            'parameters': {
                'type': 'object',
                'properties': {
                    'query': {'type': 'string', 'description': 'Search query'}
                },
                'required': ['query']
            }
        }
    }
]

# Universal tool executor
async def execute_custom_tool(tool_call):
    name = tool_call['function']['name']
    args = json.loads(tool_call['function']['arguments'])
    
    if name == 'calculator':
        result = eval(args['expression'])  # Use a safe math library in production
        return {
            'role': 'tool',
            'tool_call_id': tool_call['id'],
            'name': name,
            'content': json.dumps({'result': result, 'expression': args['expression']})
        }
    elif name == 'web_search':
        search_results = await perform_web_search(args['query'])
        return {
            'role': 'tool',
            'tool_call_id': tool_call['id'],
            'name': name,
            'content': json.dumps({'query': args['query'], 'results': search_results})
        }
    else:
        return {
            'role': 'tool',
            'tool_call_id': tool_call['id'],
            'name': name,
            'content': json.dumps({'error': 'Tool not implemented'})
        }

# Complex query requiring multiple tools
messages = [
    {'role': 'user', 'content': 'Calculate 25*4 and then search for information about that number'}
]

while True:
    final_answer_received = False
    
    async for result in agent.run(messages, {'tools': tools}):
        if result['type'] == 'plan':
            print('Plan:', result['plan'])
            
            # Add plan to messages
            messages.append({
                'role': 'assistant',
                'content': result['content'],
                'type': 'agent_plan'
            })
        
        if result['type'] == 'tool_calls':
            print('Executing tools:', [t['function']['name'] for t in result['tool_calls']])
            
            # Add tool call message
            messages.append({
                'role': 'assistant',
                'content': '',
                'tool_calls': result['tool_calls']
            })
            
            # Execute all tools
            for tool_call in result['tool_calls']:
                tool_result = await execute_custom_tool(tool_call)
                messages.append(tool_result)
                print(f"{tool_call['function']['name']} result:", tool_result['content'])
            
            # Break to continue the planning loop
            break
        
        if result['type'] == 'final_answer':
            print('Final Answer:', result['content'])
            final_answer_received = True
            break
    
    if final_answer_received:
        break
```

### Example 6: Streaming Responses

```python
streaming_agent = USFAgent({
    'api_key': 'your-api-key',
    'stream': True  # Enable streaming
})

async for result in streaming_agent.run('Tell me a story'):
    if result['type'] == 'final_answer':
        print(result['content'], end='')  # Stream content as it arrives
```

### Example 7: Memory Management

```python
agent = USFAgent({
    'api_key': 'your-api-key',
    'temp_memory': {
        'enabled': True,
        'max_length': 20,
        'auto_trim': True
    }
})

# Memory is automatically managed
async for result in agent.run('My name is John'):
    if result['type'] == 'final_answer':
        break

async for result in agent.run('What is my name?'):  # Agent remembers
    if result['type'] == 'final_answer':
        print(result['content'])
        break

# Manual memory management
print('Current memory:', agent.get_memory())
agent.clear_memory()  # Clear all memory
agent.set_memory([...])  # Set specific memory state
```

### Example 8: Per-Request Overrides

```python
# Override configurations for specific requests
async for result in agent.run(messages, {
    'tools': [...],
    'max_loops': 50,              # Allow more loops for complex requests
    
    # Override planning for this request
    'planning': {
        'model': 'usf-mini',
        'introduction': 'You are a specialized assistant for this task'
    },
    
    # Override final response
    'final_response': {
        'temperature': 0.9,
        'model': 'usf-mini-x1'
    }
}):
    if result['type'] == 'final_answer':
        response = result['content']
        break
```

## 🔧 API Reference

### Constructor Options

```python
from typing import Dict, List, Optional, Union, Any

class USFAgent:
    def __init__(self, config: Dict[str, Any]):
        """
        Initialize USF Agent with configuration.
        
        Args:
            config: Configuration dictionary with the following options:
            
            # Required
            api_key: str
            
            # Optional global settings
            base_url: str = 'https://api.us.inc/usf/v1'
            model: str = 'usf-mini'
            introduction: str = ''
            knowledge_cutoff: str = '15 January 2025'
            stream: bool = False
            max_loops: int = 20  # Range: 1-100
            
            # User context (applies to all stages)
            backstory: str = ''
            goal: str = ''
            
            # Stage-specific configurations
            planning: Dict[str, Any] = {}
            tool_calling: Dict[str, Any] = {}
            final_response: Dict[str, Any] = {}
            
            # Memory configuration
            temp_memory: Dict[str, Any] = {
                'enabled': False,
                'max_length': 10,
                'auto_trim': True
            }
        """
```

### Methods

#### `run(messages, options=None)`

Execute the agent workflow.

```python
async def run(
    self,
    messages: Union[str, List[Dict[str, Any]]],
    options: Optional[Dict[str, Any]] = None
) -> AsyncGenerator[Dict[str, Any], None]:
    """
    Execute the agent workflow.
    
    Args:
        messages: String or list of message objects
        options: Optional configuration overrides
        
    Yields:
        Dict with keys:
        - type: 'plan' | 'tool_calls' | 'final_answer'
        - content: str (optional)
        - plan: str (optional)
        - final_decision: str (optional)
        - agent_status: str (optional)
        - tool_choice: Any (optional)
        - tool_calls: List[Dict] (optional)
    """
```

#### `clear_memory()`

Clear all conversation memory.

#### `get_memory()`

Get current memory state.

#### `set_memory(messages)`

Set specific memory state.

## 🎯 Best Practices

### Tool Execution Patterns

```python
# Proper tool execution pattern - Continue until final answer
messages = [{'role': 'user', 'content': 'Your query here'}]

while True:
    final_answer_received = False
    
    async for result in agent.run(messages, {'tools': tools}):
        if result['type'] == 'plan':
            # Add plan to messages
            messages.append({
                'role': 'assistant',
                'content': result['content'],
                'type': 'agent_plan'
            })
        
        if result['type'] == 'tool_calls':
            # Add tool call message
            messages.append({
                'role': 'assistant',
                'content': '',
                'tool_calls': result['tool_calls']
            })
            
            # Execute all tools
            for tool_call in result['tool_calls']:
                tool_result = await execute_custom_tool(tool_call)
                messages.append(tool_result)
            
            # Break to continue the planning loop
            break
        
        if result['type'] == 'final_answer':
            print('Final Answer:', result['content'])
            final_answer_received = True
            break
    
    if final_answer_received:
        break
```

### Error Handling

```python
try:
    async for result in agent.run(messages):
        # Handle results
        pass
except Exception as error:
    if 'USFAgent API Error' in str(error):
        print('API Error:', str(error))
    elif 'USFAgent Network Error' in str(error):
        print('Network Error:', str(error))
    else:
        print('Unknown Error:', str(error))
```

### Configuration Recommendations

```python
# Development setup
dev_agent = USFAgent({
    'api_key': 'dev-key',
    'model': 'usf-mini',        # Fast for development
    'final_response': {
        'temperature': 0.7         # Deterministic responses
    }
})

# Production setup
prod_agent = USFAgent({
    'planning': {
        'model': 'usf-mini',
    },
    'tool_calling': {
        'model': 'usf-mini-x1'        # Better tool calling
    },
    'final_response': {
        'base_url': 'https://api.us.inc/usf/v1',
        'model': 'usf-mini',          # Fast and high-quality responses
        'temperature': 0.7
    }
})
```

## 🔍 Troubleshooting

### Common Issues

**API Key Errors:**
```
USFAgent API Error: Invalid API key
```
- Verify your API key is correct
- Check API key permissions
- Ensure the key is not expired

**Network Errors:**
```
USFAgent Network Error: Cannot connect to USF API
```
- Check internet connection
- Verify endpoint URL is accessible
- Check firewall settings

**Tool Execution Errors:**
- Ensure tool results have `role: "tool"`
- Include `tool_call_id` in tool results
- Validate tool result JSON format

**Response Format Errors:**
```
BadRequestError: Response format is not allowed with tools
```
- This error has been fixed in the latest version
- The issue was caused by sending empty `tools: []` parameter to the API
- Update to the latest version to resolve this issue

### Debug Mode

Enable comprehensive debug logging to see detailed API call information:

```python
# Enable debug mode in configuration
agent = USFAgent({
    'api_key': 'your-api-key',
    'debug': True,  # Enable debug mode
    'model': 'usf-mini'
})

# Debug mode will show:
# - Complete request URLs and headers (with masked API keys)
# - Full request payloads sent to APIs
# - Response status and data
# - Error details with request context
# - JSON parsing information

# Example debug output:
"""
DEBUG: Planning API Call
{
  "url": "https://api.us.inc/usf/v1/usf-agent/plan",
  "method": "POST",
  "headers": {
    "apiKey": "sk-1234567890...abcd",
    "Content-Type": "application/json"
  },
  "payload": {
    "messages": [...],
    "tools": [...],
    "base_url": "https://api.us.inc/usf/v1",
    "model": "usf-mini"
  }
}
"""
```

### Debug Mode Configuration

```python
# Global debug mode
agent = USFAgent({
    'api_key': 'your-api-key',
    'debug': True,  # Applies to all stages
})

# Stage-specific debug mode
agent = USFAgent({
    'api_key': 'your-api-key',
    'planning': {
        'debug': True  # Only debug planning calls
    },
    'final_response': {
        'debug': True  # Only debug final response calls
    }
})

# Per-request debug override
async for result in agent.run(messages, {
    'final_response': {
        'debug': True  # Enable debug for this request only
    }
}):
    pass
```

### Advanced Debugging

Check the agent's internal state for configuration issues:

```python
print('Planning Config:', agent.planning_config)
print('Tool Calling Config:', agent.tool_calling_config)
print('Final Response Config:', agent.final_response_config)
print('Current Memory:', agent.get_memory())

# Validate configuration
try:
    agent._validate_configuration()
    print("Configuration is valid")
except Exception as error:
    print(f"Configuration error: {error}")
```

### Debug Example Script

See `debug_example.py` for a complete example of using debug mode:

```python
# Run the debug example
python debug_example.py
```

This will demonstrate debug output for all API calls and help you understand what data is being sent to the APIs.

## 📄 License

**USF Agents SDK License**

Copyright (c) 2025 UltraSafe AI Team

**PERMITTED USE:**
- Anyone may use this software for any purpose

**RESTRICTED ACTIVITIES:**
- No one may modify the code
- No one may use the code for commercial purposes
- No one may use the code to create competitive products

**ATTRIBUTION:**
- All copies of this software must retain this license notice
- Any use of this software must include attribution to UltraSafe AI Team

## 🤝 Contributing

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

## 📞 Support

For issues and questions:
- Check the troubleshooting section above
- Review the examples for common patterns
- Ensure you're following the three-stage workflow correctly

---

**USF Agent SDK** - Flexible, powerful, and easy to use. Build intelligent agents with complete control over tool execution and model selection.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "usf-agents",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "multi-agent, orchestration, framework, lightweight, agent, developer-friendly, visibility, control, complex-usecase, simple-usecase, all-models, openai-compatible, llm, ai-agent, tool-calling, streaming, usf, planning, UltraSafe, UltraSafe AI, usf-agents",
    "author": "UltraSafe AI Team",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/b7/18/e79c05f9f17f659f67ecfc59cbb3f95827c9dec9b017e0d7f0be702be6b3/usf_agents-2.2.0.tar.gz",
    "platform": null,
    "description": "# USF Agent SDK\n\nA flexible, OpenAI-compatible Agent SDK that provides intelligent planning and tool execution capabilities using the official USF Agent SDK APIs.\n\n## \ud83d\ude80 Features\n\n- **Multi-Stage Configuration** - Different models for planning, tool calling, and final responses\n- **Manual Tool Execution** - Complete user control over tool implementations\n- **Provider Flexibility** - Mix different LLM providers (USF, OpenAI, Anthropic, etc.)\n- **Memory Management** - Built-in conversation memory with auto-trimming\n- **Streaming Support** - Real-time response streaming\n- **Automatic Date/Time Appending** - All final responses include current UTC timestamp\n- **Date/Time Override** - Custom date, time, and timezone configuration support\n- **Extra Parameters Support** - Pass any OpenAI API parameters for advanced control\n- **Type Hints Support** - Full type annotations included\n\n## \ud83d\udce6 Installation\n\n```bash\npip install usf-agents\n```\n\n## \ud83c\udfaf Quick Start\n\n```python\nfrom usf_agents import USFAgent\n\n# Basic configuration\nagent = USFAgent({\n    'api_key': 'your-usf-api-key',\n    'model': 'usf-mini'\n})\n\n# Simple query without tools\nasync for result in agent.run('Hello, how are you?'):\n    if result['type'] == 'final_answer':\n        print('Response:', result['content'])\n```\n\n## \ud83d\udd04 Core Workflow\n\nThe USF Agent follows a three-stage workflow:\n\n```\nUser Request \u2192 Plan \u2192 Tool/Agent Call \u2192 Tool/Agent Execution \u2192 Plan \u2192 ... \u2192 Plan \u2192 Final Response\n```\n\n1. **Planning Stage** - Agent analyzes the request and decides if tools are needed\n2. **Tool Calling Stage** - Agent generates tool calls in OpenAI format (if needed)\n3. **Final Response Stage** - Agent generates the final user-facing response\n\n\n## \u2699\ufe0f Configuration\n\n### Basic Configuration\n\n```python\nagent = USFAgent({\n    'api_key': 'your-api-key',                    # Required\n    'base_url': 'https://api.us.inc/usf/v1',      # Default USF endpoint\n    'model': 'usf-mini',                          # Default model\n    'introduction': 'You are a helpful AI',       # Custom system prompt\n    'knowledge_cutoff': '15 January 2025',        # Knowledge cutoff date\n    'stream': False,                              # Enable streaming\n    'max_loops': 20,                              # Maximum planning/tool loops (default: 20)\n    \n    # User context (applies to all stages)\n    'backstory': 'I am a software engineer working on improving user experience.',\n    'goal': 'Create intuitive and efficient solutions for users.',\n    \n    # Memory configuration\n    'temp_memory': {\n        'enabled': True,\n        'max_length': 10,\n        'auto_trim': True\n    }\n})\n```\n\n## \ud83d\udc64 User Context: Backstory and Goal\n\nThe USF Agent SDK supports user context through `backstory` and `goal` parameters that provide personality and objective guidance to enhance agent interactions.\n\n### Basic Usage\n\n```python\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a software engineer working on improving user experience for our application.',\n    'goal': 'Create intuitive and efficient solutions that help users accomplish their tasks quickly.'\n})\n```\n\n### How It Works\n\n- **Planning & Tool Calling**: Backstory and goal are passed directly as API parameters to `usf-agent/plan` and `usf-agent/tool-call` endpoints\n- **Final Response**: When generating the final response, backstory and goal are added to the system message to provide context\n- **Consistency**: The same backstory and goal apply to all stages of the agent workflow\n- **Memory**: Backstory and goal context is maintained throughout the conversation\n\n### Advanced Examples\n\n```python\n# Customer service agent\ncustomer_service_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a customer service representative with 5 years of experience helping customers resolve technical issues.',\n    'goal': 'Provide helpful, empathetic, and efficient support to resolve customer problems quickly.',\n    'model': 'usf-mini'\n})\n\n# Research assistant\nresearch_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a research scientist with expertise in data analysis and academic writing.',\n    'goal': 'Provide accurate, well-sourced information and help users understand complex topics.',\n    'final_response': {\n        'temperature': 0.3  # More factual responses\n    }\n})\n\n# Creative writing assistant\ncreative_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a creative writer and storyteller with a passion for engaging narratives.',\n    'goal': 'Help users craft compelling stories and improve their writing skills.',\n    'final_response': {\n        'temperature': 0.8,  # More creative responses\n        'presence_penalty': 0.2\n    }\n})\n```\n\n### Context Enhancement using backstory and goal\n\nWhen backstory and goal are provided, they automatically enhance the agent's understanding and response quality. The agent uses this context to provide more personalized and relevant responses.\n\n```python\n# Example 1: Technical support context\nsupport_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a product manager at a tech startup focusing on mobile applications.',\n    'goal': 'Improve user engagement and retention through better UX design.'\n})\n\n# Example 2: Development context\ntechnical_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a senior developer debugging performance issues in our microservices architecture.',\n    'goal': 'Identify bottlenecks and optimize system performance to handle 10x more traffic.'\n})\n\n# Example 3: Marketing context\ncontent_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a marketing manager creating content for our B2B SaaS platform.',\n    'goal': 'Generate compelling content that converts prospects into customers.'\n})\n\n# The agent will use this context throughout the conversation\nasync for result in support_agent.run('How can I improve our app\\'s user onboarding?'):\n    if result['type'] == 'final_answer':\n        print(result['content'])\n        break\n\nasync for result in technical_agent.run('Our API response times are slow, what should I investigate?'):\n    if result['type'] == 'final_answer':\n        print(result['content'])\n        break\n\nasync for result in content_agent.run('Write a blog post about our new feature.'):\n    if result['type'] == 'final_answer':\n        print(result['content'])\n        break\n```\n\n### Best Practices\n\n```python\n# \u2705 Good: Specific and relevant backstory\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am a frontend developer working on a React application for e-commerce.',\n    'goal': 'Build responsive, accessible components that improve user conversion rates.'\n})\n\n# \u274c Avoid: Vague or irrelevant context\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I like computers.',\n    'goal': 'Do stuff.'\n})\n\n# \u2705 Good: Task-specific context\ndebugging_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'backstory': 'I am debugging a Python application that handles user authentication.',\n    'goal': 'Identify and fix the root cause of authentication failures in production.'\n})\n```\n\n### Multi-Stage Configuration\n\nUse different models for each stage to optimize cost and performance:\n\n```python\nagent = USFAgent({\n    # Default fallback configuration\n    'api_key': 'default-key',\n    'base_url': 'https://api.us.inc/usf/v1',\n    'model': 'usf-mini',\n    \n    # Planning stage - Use powerful model for complex reasoning\n    'planning': {\n        'api_key': 'planning-key',\n        'model': 'usf-mini',\n        'introduction': 'You are an expert planning assistant.'\n    },\n    \n    # Tool calling stage - Use fast model for efficiency\n    'tool_calling': {\n        'api_key': 'tool-key',\n        'model': 'usf-mini-x1'\n    },\n    \n    # Final response stage - Use different provider\n    'final_response': {\n        'api_key': 'api-key',\n        'base_url': 'https://api.us.inc/usf/v1',\n        'model': 'usf-mini',\n        'temperature': 0.7\n    }\n})\n```\n\n## \ud83d\udd52 Automatic Date/Time Feature\n\nThe USF Agent SDK automatically appends the current date and time to all final responses. This feature:\n\n- **Always Active** - No configuration required, works automatically\n- **UTC Timezone** - Consistent timezone for all responses\n- **Format**: `Current date: MM/DD/YYYY, HH:MM:SS AM/PM (UTC Timezone).`\n- **Universal Coverage** - Works with both streaming and non-streaming modes\n- **All Response Paths** - Applies to both OpenAI-based and legacy response generation\n\n### Example Output\n\n```python\n# User query: \"What is the capital of France?\"\n# Agent response will end with:\n\"Current system time is 5:54 AM (UTC).\"\n```\n\n### Technical Details\n\nThe date/time is automatically injected during the message processing phase, ensuring that:\n- The LLM receives instructions to include the timestamp\n- The timestamp reflects the exact moment of response generation\n- No additional API calls or processing overhead\n- Consistent format across all responses\n\n### Date/Time Override\n\nYou can override the default UTC timestamp with custom date, time, and timezone:\n\n#### Static Date/Time Override\n\n```python\n# Global configuration with static override\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        'date_time_override': {\n            'enabled': True,\n            'date': '12/25/2025',        # MM/DD/YYYY format required\n            'time': '11:30:45 PM',       # HH:MM:SS AM/PM format required\n            'timezone': 'EST'            # Any timezone string\n        }\n    }\n})\n\n# Per-request override\nasync for result in agent.run('What time is it?', {\n    'date_time_override': {\n        'enabled': True,\n        'date': '01/01/2026',\n        'time': '12:00:00 AM',\n        'timezone': 'UTC'\n    }\n}):\n    if result['type'] == 'final_answer':\n        response = result['content']\n        break\n```\n\n#### Dynamic/Real-time Date/Time Override\n\n```python\nimport datetime\nfrom zoneinfo import ZoneInfo\n\n# Function to get current time in specific timezone\ndef get_current_time_in_timezone(timezone):\n    now = datetime.datetime.now(ZoneInfo(timezone))\n    \n    return {\n        'date': now.strftime('%m/%d/%Y'),\n        'time': now.strftime('%I:%M:%S %p'),\n        'timezone': timezone\n    }\n\n# Dynamic override for different timezones\ntokyo_time = get_current_time_in_timezone('Asia/Tokyo')\nasync for result in agent.run('What time is it in Tokyo?', {\n    'date_time_override': {\n        'enabled': True,\n        **tokyo_time\n    }\n}):\n    if result['type'] == 'final_answer':\n        response = result['content']\n        break\n\n# Multiple timezone examples\ntimezones = [\n    'America/New_York',\n    'Europe/London', \n    'Asia/Tokyo',\n    'Australia/Sydney',\n    'America/Los_Angeles'\n]\n\nfor tz in timezones:\n    time_data = get_current_time_in_timezone(tz)\n    async for result in agent.run(f'What\\'s happening now in {tz}?', {\n        'date_time_override': {\n            'enabled': True,\n            **time_data\n        }\n    }):\n        if result['type'] == 'final_answer':\n            response = result['content']\n            break\n```\n\n#### Timezone Format Examples\n\n```python\n# Various supported timezone formats\ntimezone_examples = [\n    # Standard abbreviations\n    {'timezone': 'EST', 'description': 'Eastern Standard Time'},\n    {'timezone': 'PST', 'description': 'Pacific Standard Time'},\n    {'timezone': 'GMT', 'description': 'Greenwich Mean Time'},\n    \n    # Full timezone names\n    {'timezone': 'Eastern Standard Time', 'description': 'Full name'},\n    {'timezone': 'Pacific Standard Time', 'description': 'Full name'},\n    \n    # UTC offsets\n    {'timezone': 'UTC-5', 'description': 'UTC offset negative'},\n    {'timezone': 'UTC+9', 'description': 'UTC offset positive'},\n    \n    # IANA timezone identifiers (recommended)\n    {'timezone': 'America/New_York', 'description': 'IANA identifier'},\n    {'timezone': 'Europe/London', 'description': 'IANA identifier'},\n    {'timezone': 'Asia/Tokyo', 'description': 'IANA identifier'},\n    {'timezone': 'Australia/Sydney', 'description': 'IANA identifier'}\n]\n```\n\n#### Validation and Fallback\n\n```python\n# Invalid formats automatically fallback to UTC\ninvalid_examples = [\n    {\n        'enabled': True,\n        'date': '2025-12-25',      # Wrong format (YYYY-MM-DD)\n        'time': '23:30:45',        # Wrong format (24-hour)\n        'timezone': 'EST'\n    },\n    {\n        'enabled': True,\n        'date': '12/25/2025',\n        'time': '11:30:45 PM'\n        # Missing timezone\n    },\n    {\n        'enabled': False,           # Disabled override\n        'date': '12/25/2025',\n        'time': '11:30:45 PM',\n        'timezone': 'EST'\n    }\n]\n\n# All above examples will fallback to UTC automatically\n```\n\n## \ud83d\udd27 Extra Parameters Support\n\nThe USF Agent SDK supports passing any additional OpenAI API parameters directly to the final response generation. This provides full access to OpenAI's chat completion capabilities.\n\n### Basic Extra Parameters\n\n```python\n# Global configuration with extra parameters\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        # Standard parameters\n        'temperature': 0.7,\n        'stop': ['END'],\n        \n        # Extra OpenAI parameters\n        'max_tokens': 1000,\n        'top_p': 0.9,\n        'presence_penalty': 0.1,\n        'frequency_penalty': 0.2,\n        'seed': 12345,\n        'user': 'user-123'\n    }\n})\n```\n\n### Structured Output with JSON Schema\n\n```python\n# Complex response_format with JSON schema\nstructured_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        'response_format': {\n            'type': 'json_schema',\n            'json_schema': {\n                'name': 'book_info',\n                'strict': True,\n                'schema': {\n                    'type': 'object',\n                    'properties': {\n                        'title': {\n                            'type': 'string',\n                            'description': 'Title of the book'\n                        },\n                        'author': {\n                            'type': 'string', \n                            'description': 'Author of the book'\n                        },\n                        'year_published': {\n                            'type': 'number',\n                            'description': 'Year the book was first published'\n                        },\n                        'genre': {\n                            'type': 'string',\n                            'enum': ['fiction', 'non-fiction', 'mystery', 'romance', 'sci-fi'],\n                            'description': 'Genre of the book'\n                        },\n                        'rating': {\n                            'type': 'number',\n                            'minimum': 1,\n                            'maximum': 5,\n                            'description': 'Rating out of 5 stars'\n                        }\n                    },\n                    'required': ['title', 'author', 'year_published'],\n                    'additionalProperties': False\n                }\n            }\n        },\n        'temperature': 0.1  # Low temperature for consistent JSON\n    }\n})\n\n# This will force structured JSON output\nasync for result in structured_agent.run('Tell me about the book \"1984\"'):\n    if result['type'] == 'final_answer':\n        book_info = result['content']\n        break\n```\n\n### Advanced Parameter Examples\n\n```python\n# Token control with logit_bias\nbiased_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        'logit_bias': {\n            '1820': 10,     # Boost 'positive' token\n            '4633': -10,    # Reduce 'negative' token  \n            '50256': -100   # Avoid end-of-text token\n        },\n        'temperature': 0.8\n    }\n})\n\n# Deterministic responses with seed\ndeterministic_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        'seed': 42,\n        'temperature': 0.7  # Same seed + temp = consistent results\n    }\n})\n\n# Creative writing with penalties\ncreative_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        'presence_penalty': 0.6,   # Encourage new topics\n        'frequency_penalty': 0.3,  # Reduce repetition\n        'temperature': 0.9,        # High creativity\n        'max_tokens': 500\n    }\n})\n\n# Streaming with usage tracking\nstreaming_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'stream': True,\n    'final_response': {\n        'stream_options': {\n            'include_usage': True\n        },\n        'max_tokens': 200\n    }\n})\n```\n\n### Per-Request Parameter Override\n\n```python\n# Mix global and per-request parameters\nflexible_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        'temperature': 0.7,  # Global default\n        'max_tokens': 500    # Global default\n    }\n})\n\n# Request 1: JSON output\nasync for result in flexible_agent.run('List 3 colors', {\n    'final_response': {\n        'response_format': {'type': 'json_object'},\n        'temperature': 0.1,  # Override global\n        'max_tokens': 100    # Override global\n    }\n}):\n    if result['type'] == 'final_answer':\n        json_response = result['content']\n        break\n\n# Request 2: Creative writing\nasync for result in flexible_agent.run('Write a short story', {\n    'final_response': {\n        'temperature': 0.9,      # Override global\n        'presence_penalty': 0.4, # Add new parameter\n        'max_tokens': 800,       # Override global\n        'stop': ['THE END']      # Add stop sequence\n    }\n}):\n    if result['type'] == 'final_answer':\n        story_response = result['content']\n        break\n\n# Request 3: Deterministic output\nasync for result in flexible_agent.run('What is 2+2?', {\n    'final_response': {\n        'seed': 123,\n        'temperature': 0.0,  # Most deterministic\n        'max_tokens': 50\n    }\n}):\n    if result['type'] == 'final_answer':\n        fact_response = result['content']\n        break\n```\n\n### Combining Date/Time Override with Extra Parameters\n\n```python\n# Use both features together\ncombined_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'final_response': {\n        # Date/time override\n        'date_time_override': {\n            'enabled': True,\n            'date': '12/31/2025',\n            'time': '11:59:59 PM',\n            'timezone': 'EST'\n        },\n        \n        # Extra OpenAI parameters\n        'response_format': {\n            'type': 'json_schema',\n            'json_schema': {\n                'name': 'year_end_summary',\n                'schema': {\n                    'type': 'object',\n                    'properties': {\n                        'year': {'type': 'number'},\n                        'summary': {'type': 'string'},\n                        'predictions': {\n                            'type': 'array',\n                            'items': {'type': 'string'}\n                        }\n                    },\n                    'required': ['year', 'summary']\n                }\n            }\n        },\n        'max_tokens': 800,\n        'temperature': 0.5\n    }\n})\n```\n\n### Supported Extra Parameters\n\n| Parameter | Type | Description | Example |\n|-----------|------|-------------|---------|\n| `response_format` | dict | Control output format | `{'type': \"json_object\"}` |\n| `max_tokens` | int | Maximum response length | `1000` |\n| `top_p` | float | Nucleus sampling (0-1) | `0.9` |\n| `presence_penalty` | float | New topic penalty (-2 to 2) | `0.1` |\n| `frequency_penalty` | float | Repetition penalty (-2 to 2) | `0.2` |\n| `logit_bias` | dict | Token probability control | `{\"50256\": -100}` |\n| `seed` | int | Deterministic output | `12345` |\n| `user` | str | User identifier | `\"user-123\"` |\n| `stream_options` | dict | Streaming configuration | `{'include_usage': True}` |\n\n### Important Notes\n\n- **Scope**: Extra parameters only apply to final response generation\n- **Validation**: Parameter validation is handled by the OpenAI API\n- **Errors**: Invalid parameters will cause API errors (passed through directly)\n- **Future-Proof**: Any new OpenAI parameters are automatically supported\n- **Planning/Tools**: Extra parameters are ignored by planning and tool calling APIs\n\n## \ud83e\udde0 Advanced Multi-Agent Orchestration\n\nThe SDK now includes a flexible multi-agent orchestration layer on top of `USFAgent` that supports:\n- Manager/SubAgent composition with agent-as-tool delegation\n- Strict isolation (sub-agent tools/memory are never exposed)\n- 4 context transfer modes:\n  - NONE: do not pass caller messages\n  - AGENT_DECIDED: pass full context only if the caller supplied it\n  - ALWAYS_FULL: pass complete parent messages in OpenAI format\n  - CONTEXT_PARAM: pass only an explicit lightweight context object\n- Graph workflows (LangGraph-style) with nodes (agents/tools) and conditional edges\n- Full trace recording and pre/post-execution visualization (Mermaid/Graphviz/JSON)\n\nPublic API quick import:\n```python\nfrom usf_agents import (\n  USFAgent,\n  # Multi-agent\n  SubAgent, ManagerAgent, AgentRegistry,\n  WorkflowGraph, ExecutionEngine,\n  TraceRecorder, TraceStore,\n  to_mermaid, to_graphviz, trace_to_json\n)\n```\n\n### Example A: SubAgent delegation with isolation\n\n```python\nimport asyncio\nfrom usf_agents import SubAgent, ManagerAgent\n\n# Create isolated sub-agents\nmath_agent = SubAgent({\n    'id': 'math',\n    'name': 'Math Specialist',\n    'agent_type': 'sub',\n    'context_mode': 'NONE',   # default: do not pass parent transcript\n    'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}\n})\n\ncode_agent = SubAgent({\n    'id': 'coder',\n    'name': 'Code Assistant',\n    'agent_type': 'sub',\n    'context_mode': 'CONTEXT_PARAM',  # pass only lightweight context objects\n    'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}\n})\n\n# Manager agent\nmanager = ManagerAgent({\n    'id': 'mgr',\n    'name': 'Manager',\n    'agent_type': 'manager',\n    'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}\n})\n\n# Register sub-agents as callable tools for the manager\nmanager.add_sub_agent(math_agent, {\n  'description': 'Delegate math tasks',\n  'parameters': {\n    'type': 'object',\n    'properties': {\n      'task': {'type': 'string'},\n      'input': {'type': 'object'},\n      'context_param': {'type': 'object'}\n    },\n    'required': ['task']\n  }\n}, alias='math_tool')\n\nmanager.add_sub_agent(code_agent, {\n  'description': 'Delegate coding tasks',\n  'parameters': {\n    'type': 'object',\n    'properties': {\n      'task': {'type': 'string'},\n      'input': {'type': 'object'},\n      'context_param': {'type': 'object'}\n    },\n    'required': ['task']\n  }\n}, alias='coder_tool')\n\nasync def main():\n    # Delegation with sub-agent policy NONE (no parent transcript)\n    math_res = await manager.delegate(\n        sub_id='math',\n        task={'task': 'calculate', 'input': {'expression': '25 * 4'}}\n    )\n    print('Math result:', math_res)\n\n    # Delegation with lightweight explicit context\n    code_res = await manager.delegate(\n        sub_id='coder',\n        task={'task': 'generate_function', 'input': {'language': 'python', 'spec': 'sum(a,b)'}},\n        policy='CONTEXT_PARAM',\n        context_param={'style': 'concise'}\n    )\n    print('Code result:', code_res)\n\nasyncio.run(main())\n```\n\n### Example B: 4 Context Modes\n\n- NONE \u2192 Only the new task is passed to sub-agent.\n- AGENT_DECIDED \u2192 Behaves like ALWAYS_FULL if caller messages are present, else NONE.\n- ALWAYS_FULL \u2192 Pass full caller transcript + delegated task.\n- CONTEXT_PARAM \u2192 Pass only a small explicit context object + delegated task.\n\nOverride per call:\n```python\nawait manager.delegate(sub_id='math', task={...}, policy='ALWAYS_FULL', context_param=None)\n```\n\n### Example C: Graph workflow with conditional edges\n\n```python\nimport asyncio\nfrom usf_agents import SubAgent, AgentRegistry, WorkflowGraph, ExecutionEngine, TraceRecorder, to_mermaid\n\na = SubAgent({'id': 'A','name': 'Agent A','agent_type': 'sub','context_mode': 'NONE','usf_config': {'api_key': 'YOUR_API_KEY','model': 'usf-mini'}})\nb = SubAgent({'id': 'B','name': 'Agent B','agent_type': 'sub','context_mode': 'CONTEXT_PARAM','usf_config': {'api_key': 'YOUR_API_KEY','model': 'usf-mini'}})\n\nreg = AgentRegistry()\nreg.add_agent(a)\nreg.add_agent(b)\n\nspec = {\n  'nodes': [\n    {'id': 'nodeA', 'type': 'agent', 'ref': 'A'},\n    {'id': 'nodeB', 'type': 'agent', 'ref': 'B'}\n  ],\n  'edges': [\n    {'source': 'nodeA', 'target': 'nodeB', 'condition': 'last.success == true'}\n  ]\n}\ngraph = WorkflowGraph(spec)\nrecorder = TraceRecorder()\nengine = ExecutionEngine(graph, reg, recorder)\n\nasync def run():\n    inputs = {\n      'nodeA': {'task': 'greet', 'input': {'name': 'Alice'}},\n      'nodeB': {'task': 'followup', 'input': {'topic': 'status'}}\n    }\n    outputs = await engine.run(entry_nodes=['nodeA'], inputs=inputs, max_steps=20)\n    print('Outputs:', outputs)\n    print('Mermaid:\\n', to_mermaid(spec, recorder.snapshot()))\n\nasyncio.run(run())\n```\n\n### Example D: Trace and visualization\n\n```python\nfrom usf_agents import TraceRecorder, to_mermaid, to_graphviz, trace_to_json\n# Use TraceRecorder during workflow execution; then render:\ndiagram = to_mermaid(graph_spec, trace)  # Flowchart with [visited] annotations\ndot = to_graphviz(graph_spec, trace)     # DOT format for Graphviz\nprint(trace_to_json(trace))              # Pretty JSON for logs\n```\n\n### Example E: Agent-as-tool adapter (classic tool_call path)\n\n```python\nimport asyncio, json\nfrom usf_agents import SubAgent\nfrom usf_agents.multi_agent import make_agent_tool, handle_agent_tool_call\n\nsub = SubAgent({\n  'id': 'worker',\n  'name': 'Worker',\n  'agent_type': 'sub',\n  'context_mode': 'AGENT_DECIDED',\n  'usf_config': {'api_key': 'YOUR_API_KEY', 'model': 'usf-mini'}\n})\n\ntool_def = make_agent_tool(sub, {'description': 'Invoke worker sub-agent'})\ntool_call = {\n  'id': 'call_1',\n  'type': 'function',\n  'function': {'name': tool_def['function']['name'], 'arguments': json.dumps({'task': 'do_work','input': {'x': 1}})}\n}\n\nasync def run():\n    res = await handle_agent_tool_call(sub, tool_call, calling_context=None, mode='AGENT_DECIDED')\n    print(res)\n\nasyncio.run(run())\n```\n\nFor more recipes, see `usf_agents/examples/multi_agent_examples.md`.\n\n## \ud83d\udcda Usage Examples\n\n### Example 1: Simple Query (No Tools)\n\n```python\nfrom usf_agents import USFAgent\n\nagent = USFAgent({\n    'api_key': 'your-api-key'\n})\n\nasync for result in agent.run('What is 2 + 2?'):\n    print(f\"{result['type']}:\", result.get('content') or result.get('plan'))\n```\n\n### Example 2: Weather Query with Tool Execution\n\n```python\n# Define your tools\ntools = [\n    {\n        'type': 'function',\n        'function': {\n            'name': 'get_weather',\n            'description': 'Get current weather for a location',\n            'parameters': {\n                'type': 'object',\n                'properties': {\n                    'location': {'type': 'string', 'description': 'City name'}\n                },\n                'required': ['location']\n            }\n        }\n    }\n]\n\n# Custom tool execution function\nasync def execute_weather_tool(tool_call):\n    name = tool_call['function']['name']\n    args = json.loads(tool_call['function']['arguments'])\n    \n    # Your custom weather API logic here\n    weather_data = await get_weather_from_api(args['location'])\n    \n    return {\n        'role': 'tool',\n        'tool_call_id': tool_call['id'],\n        'name': name,\n        'content': json.dumps(weather_data)\n    }\n\n# Main execution - Continue until agent provides final answer\nmessages = [\n    {'role': 'user', 'content': 'What\\'s the weather in New York?'}\n]\n\nwhile True:\n    final_answer_received = False\n    \n    async for result in agent.run(messages, {'tools': tools}):\n        if result['type'] == 'plan':\n            print('Plan:', result['plan'])\n            \n            # Add plan to messages\n            messages.append({\n                'role': 'assistant',\n                'content': result['content'],\n                'type': 'agent_plan'\n            })\n        \n        if result['type'] == 'tool_calls':\n            print('Tools to execute:', result['tool_calls'])\n            \n            # Add tool call message\n            messages.append({\n                'role': 'assistant',\n                'content': '',\n                'tool_calls': result['tool_calls']\n            })\n            \n            # Execute tools manually\n            for tool_call in result['tool_calls']:\n                tool_result = await execute_weather_tool(tool_call)\n                messages.append(tool_result)\n            \n            # Break to continue the planning loop with tool results\n            break\n        \n        if result['type'] == 'final_answer':\n            print('Final Answer:', result['content'])\n            final_answer_received = True\n            break\n    \n    # Exit if we received the final answer\n    if final_answer_received:\n        break\n```\n\n### Example 3: Cost Optimization Setup\n\n```python\ncost_optimized_agent = USFAgent({\n    # Use expensive model only for planning\n    'planning': {\n        'api_key': 'usf-key',\n        'model': 'usf-mini'  # High-quality planning\n    },\n    \n    # Use cheap model for tool calling\n    'tool_calling': {\n        'api_key': 'usf-key',\n        'model': 'usf-mini-x1'  # Better tool calling\n    },\n    \n    # Use mid-tier model for responses\n    'final_response': {\n        'api_key': 'usf-key',\n        'model': 'usf-mini'  # Fast and high quality responses\n    }\n})\n```\n\n### Example 4: Provider Mixing\n\n```python\nmixed_provider_agent = USFAgent({\n    # USF for planning and tool calling\n    'planning': {\n        'api_key': 'usf-key',\n        'base_url': 'https://api.us.inc/usf/v1',\n        'model': 'usf-mini'\n    },\n    \n    'tool_calling': {\n        'api_key': 'usf-key',\n        'base_url': 'https://api.us.inc/usf/v1',\n        'model': 'usf-mini-x1'\n    },\n    \n    # OpenAI for final responses\n    'final_response': {\n        'api_key': 'openai-key',\n        'base_url': 'https://api.openai.com/v1',\n        'model': 'gpt-4'\n    }\n})\n```\n\n### Example 5: Custom Tool Implementation\n\n```python\nimport json\n\n# Multi-tool example\ntools = [\n    {\n        'type': 'function',\n        'function': {\n            'name': 'calculator',\n            'description': 'Perform mathematical calculations',\n            'parameters': {\n                'type': 'object',\n                'properties': {\n                    'expression': {'type': 'string', 'description': 'Math expression to evaluate'}\n                },\n                'required': ['expression']\n            }\n        }\n    },\n    {\n        'type': 'function',\n        'function': {\n            'name': 'web_search',\n            'description': 'Search the web for information',\n            'parameters': {\n                'type': 'object',\n                'properties': {\n                    'query': {'type': 'string', 'description': 'Search query'}\n                },\n                'required': ['query']\n            }\n        }\n    }\n]\n\n# Universal tool executor\nasync def execute_custom_tool(tool_call):\n    name = tool_call['function']['name']\n    args = json.loads(tool_call['function']['arguments'])\n    \n    if name == 'calculator':\n        result = eval(args['expression'])  # Use a safe math library in production\n        return {\n            'role': 'tool',\n            'tool_call_id': tool_call['id'],\n            'name': name,\n            'content': json.dumps({'result': result, 'expression': args['expression']})\n        }\n    elif name == 'web_search':\n        search_results = await perform_web_search(args['query'])\n        return {\n            'role': 'tool',\n            'tool_call_id': tool_call['id'],\n            'name': name,\n            'content': json.dumps({'query': args['query'], 'results': search_results})\n        }\n    else:\n        return {\n            'role': 'tool',\n            'tool_call_id': tool_call['id'],\n            'name': name,\n            'content': json.dumps({'error': 'Tool not implemented'})\n        }\n\n# Complex query requiring multiple tools\nmessages = [\n    {'role': 'user', 'content': 'Calculate 25*4 and then search for information about that number'}\n]\n\nwhile True:\n    final_answer_received = False\n    \n    async for result in agent.run(messages, {'tools': tools}):\n        if result['type'] == 'plan':\n            print('Plan:', result['plan'])\n            \n            # Add plan to messages\n            messages.append({\n                'role': 'assistant',\n                'content': result['content'],\n                'type': 'agent_plan'\n            })\n        \n        if result['type'] == 'tool_calls':\n            print('Executing tools:', [t['function']['name'] for t in result['tool_calls']])\n            \n            # Add tool call message\n            messages.append({\n                'role': 'assistant',\n                'content': '',\n                'tool_calls': result['tool_calls']\n            })\n            \n            # Execute all tools\n            for tool_call in result['tool_calls']:\n                tool_result = await execute_custom_tool(tool_call)\n                messages.append(tool_result)\n                print(f\"{tool_call['function']['name']} result:\", tool_result['content'])\n            \n            # Break to continue the planning loop\n            break\n        \n        if result['type'] == 'final_answer':\n            print('Final Answer:', result['content'])\n            final_answer_received = True\n            break\n    \n    if final_answer_received:\n        break\n```\n\n### Example 6: Streaming Responses\n\n```python\nstreaming_agent = USFAgent({\n    'api_key': 'your-api-key',\n    'stream': True  # Enable streaming\n})\n\nasync for result in streaming_agent.run('Tell me a story'):\n    if result['type'] == 'final_answer':\n        print(result['content'], end='')  # Stream content as it arrives\n```\n\n### Example 7: Memory Management\n\n```python\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'temp_memory': {\n        'enabled': True,\n        'max_length': 20,\n        'auto_trim': True\n    }\n})\n\n# Memory is automatically managed\nasync for result in agent.run('My name is John'):\n    if result['type'] == 'final_answer':\n        break\n\nasync for result in agent.run('What is my name?'):  # Agent remembers\n    if result['type'] == 'final_answer':\n        print(result['content'])\n        break\n\n# Manual memory management\nprint('Current memory:', agent.get_memory())\nagent.clear_memory()  # Clear all memory\nagent.set_memory([...])  # Set specific memory state\n```\n\n### Example 8: Per-Request Overrides\n\n```python\n# Override configurations for specific requests\nasync for result in agent.run(messages, {\n    'tools': [...],\n    'max_loops': 50,              # Allow more loops for complex requests\n    \n    # Override planning for this request\n    'planning': {\n        'model': 'usf-mini',\n        'introduction': 'You are a specialized assistant for this task'\n    },\n    \n    # Override final response\n    'final_response': {\n        'temperature': 0.9,\n        'model': 'usf-mini-x1'\n    }\n}):\n    if result['type'] == 'final_answer':\n        response = result['content']\n        break\n```\n\n## \ud83d\udd27 API Reference\n\n### Constructor Options\n\n```python\nfrom typing import Dict, List, Optional, Union, Any\n\nclass USFAgent:\n    def __init__(self, config: Dict[str, Any]):\n        \"\"\"\n        Initialize USF Agent with configuration.\n        \n        Args:\n            config: Configuration dictionary with the following options:\n            \n            # Required\n            api_key: str\n            \n            # Optional global settings\n            base_url: str = 'https://api.us.inc/usf/v1'\n            model: str = 'usf-mini'\n            introduction: str = ''\n            knowledge_cutoff: str = '15 January 2025'\n            stream: bool = False\n            max_loops: int = 20  # Range: 1-100\n            \n            # User context (applies to all stages)\n            backstory: str = ''\n            goal: str = ''\n            \n            # Stage-specific configurations\n            planning: Dict[str, Any] = {}\n            tool_calling: Dict[str, Any] = {}\n            final_response: Dict[str, Any] = {}\n            \n            # Memory configuration\n            temp_memory: Dict[str, Any] = {\n                'enabled': False,\n                'max_length': 10,\n                'auto_trim': True\n            }\n        \"\"\"\n```\n\n### Methods\n\n#### `run(messages, options=None)`\n\nExecute the agent workflow.\n\n```python\nasync def run(\n    self,\n    messages: Union[str, List[Dict[str, Any]]],\n    options: Optional[Dict[str, Any]] = None\n) -> AsyncGenerator[Dict[str, Any], None]:\n    \"\"\"\n    Execute the agent workflow.\n    \n    Args:\n        messages: String or list of message objects\n        options: Optional configuration overrides\n        \n    Yields:\n        Dict with keys:\n        - type: 'plan' | 'tool_calls' | 'final_answer'\n        - content: str (optional)\n        - plan: str (optional)\n        - final_decision: str (optional)\n        - agent_status: str (optional)\n        - tool_choice: Any (optional)\n        - tool_calls: List[Dict] (optional)\n    \"\"\"\n```\n\n#### `clear_memory()`\n\nClear all conversation memory.\n\n#### `get_memory()`\n\nGet current memory state.\n\n#### `set_memory(messages)`\n\nSet specific memory state.\n\n## \ud83c\udfaf Best Practices\n\n### Tool Execution Patterns\n\n```python\n# Proper tool execution pattern - Continue until final answer\nmessages = [{'role': 'user', 'content': 'Your query here'}]\n\nwhile True:\n    final_answer_received = False\n    \n    async for result in agent.run(messages, {'tools': tools}):\n        if result['type'] == 'plan':\n            # Add plan to messages\n            messages.append({\n                'role': 'assistant',\n                'content': result['content'],\n                'type': 'agent_plan'\n            })\n        \n        if result['type'] == 'tool_calls':\n            # Add tool call message\n            messages.append({\n                'role': 'assistant',\n                'content': '',\n                'tool_calls': result['tool_calls']\n            })\n            \n            # Execute all tools\n            for tool_call in result['tool_calls']:\n                tool_result = await execute_custom_tool(tool_call)\n                messages.append(tool_result)\n            \n            # Break to continue the planning loop\n            break\n        \n        if result['type'] == 'final_answer':\n            print('Final Answer:', result['content'])\n            final_answer_received = True\n            break\n    \n    if final_answer_received:\n        break\n```\n\n### Error Handling\n\n```python\ntry:\n    async for result in agent.run(messages):\n        # Handle results\n        pass\nexcept Exception as error:\n    if 'USFAgent API Error' in str(error):\n        print('API Error:', str(error))\n    elif 'USFAgent Network Error' in str(error):\n        print('Network Error:', str(error))\n    else:\n        print('Unknown Error:', str(error))\n```\n\n### Configuration Recommendations\n\n```python\n# Development setup\ndev_agent = USFAgent({\n    'api_key': 'dev-key',\n    'model': 'usf-mini',        # Fast for development\n    'final_response': {\n        'temperature': 0.7         # Deterministic responses\n    }\n})\n\n# Production setup\nprod_agent = USFAgent({\n    'planning': {\n        'model': 'usf-mini',\n    },\n    'tool_calling': {\n        'model': 'usf-mini-x1'        # Better tool calling\n    },\n    'final_response': {\n        'base_url': 'https://api.us.inc/usf/v1',\n        'model': 'usf-mini',          # Fast and high-quality responses\n        'temperature': 0.7\n    }\n})\n```\n\n## \ud83d\udd0d Troubleshooting\n\n### Common Issues\n\n**API Key Errors:**\n```\nUSFAgent API Error: Invalid API key\n```\n- Verify your API key is correct\n- Check API key permissions\n- Ensure the key is not expired\n\n**Network Errors:**\n```\nUSFAgent Network Error: Cannot connect to USF API\n```\n- Check internet connection\n- Verify endpoint URL is accessible\n- Check firewall settings\n\n**Tool Execution Errors:**\n- Ensure tool results have `role: \"tool\"`\n- Include `tool_call_id` in tool results\n- Validate tool result JSON format\n\n**Response Format Errors:**\n```\nBadRequestError: Response format is not allowed with tools\n```\n- This error has been fixed in the latest version\n- The issue was caused by sending empty `tools: []` parameter to the API\n- Update to the latest version to resolve this issue\n\n### Debug Mode\n\nEnable comprehensive debug logging to see detailed API call information:\n\n```python\n# Enable debug mode in configuration\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'debug': True,  # Enable debug mode\n    'model': 'usf-mini'\n})\n\n# Debug mode will show:\n# - Complete request URLs and headers (with masked API keys)\n# - Full request payloads sent to APIs\n# - Response status and data\n# - Error details with request context\n# - JSON parsing information\n\n# Example debug output:\n\"\"\"\nDEBUG: Planning API Call\n{\n  \"url\": \"https://api.us.inc/usf/v1/usf-agent/plan\",\n  \"method\": \"POST\",\n  \"headers\": {\n    \"apiKey\": \"sk-1234567890...abcd\",\n    \"Content-Type\": \"application/json\"\n  },\n  \"payload\": {\n    \"messages\": [...],\n    \"tools\": [...],\n    \"base_url\": \"https://api.us.inc/usf/v1\",\n    \"model\": \"usf-mini\"\n  }\n}\n\"\"\"\n```\n\n### Debug Mode Configuration\n\n```python\n# Global debug mode\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'debug': True,  # Applies to all stages\n})\n\n# Stage-specific debug mode\nagent = USFAgent({\n    'api_key': 'your-api-key',\n    'planning': {\n        'debug': True  # Only debug planning calls\n    },\n    'final_response': {\n        'debug': True  # Only debug final response calls\n    }\n})\n\n# Per-request debug override\nasync for result in agent.run(messages, {\n    'final_response': {\n        'debug': True  # Enable debug for this request only\n    }\n}):\n    pass\n```\n\n### Advanced Debugging\n\nCheck the agent's internal state for configuration issues:\n\n```python\nprint('Planning Config:', agent.planning_config)\nprint('Tool Calling Config:', agent.tool_calling_config)\nprint('Final Response Config:', agent.final_response_config)\nprint('Current Memory:', agent.get_memory())\n\n# Validate configuration\ntry:\n    agent._validate_configuration()\n    print(\"Configuration is valid\")\nexcept Exception as error:\n    print(f\"Configuration error: {error}\")\n```\n\n### Debug Example Script\n\nSee `debug_example.py` for a complete example of using debug mode:\n\n```python\n# Run the debug example\npython debug_example.py\n```\n\nThis will demonstrate debug output for all API calls and help you understand what data is being sent to the APIs.\n\n## \ud83d\udcc4 License\n\n**USF Agents SDK License**\n\nCopyright (c) 2025 UltraSafe AI Team\n\n**PERMITTED USE:**\n- Anyone may use this software for any purpose\n\n**RESTRICTED ACTIVITIES:**\n- No one may modify the code\n- No one may use the code for commercial purposes\n- No one may use the code to create competitive products\n\n**ATTRIBUTION:**\n- All copies of this software must retain this license notice\n- Any use of this software must include attribution to UltraSafe AI Team\n\n## \ud83e\udd1d Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## \ud83d\udcde Support\n\nFor issues and questions:\n- Check the troubleshooting section above\n- Review the examples for common patterns\n- Ensure you're following the three-stage workflow correctly\n\n---\n\n**USF Agent SDK** - Flexible, powerful, and easy to use. Build intelligent agents with complete control over tool execution and model selection.\n",
    "bugtrack_url": null,
    "license": "USF Agents SDK License",
    "summary": "A lightweight multi-agent orchestration framework with better control, easy to use for complex to simple use cases. Developer friendly with more visibility and supports all models with OpenAI compatible API.",
    "version": "2.2.0",
    "project_urls": {
        "Bug Reports": "https://github.com/UltraSafeAI/usf-agents-python/issues",
        "Documentation": "https://us.inc/docs",
        "Homepage": "https://us.inc",
        "Repository": "https://github.com/UltraSafeAI/usf-agents-python"
    },
    "split_keywords": [
        "multi-agent",
        " orchestration",
        " framework",
        " lightweight",
        " agent",
        " developer-friendly",
        " visibility",
        " control",
        " complex-usecase",
        " simple-usecase",
        " all-models",
        " openai-compatible",
        " llm",
        " ai-agent",
        " tool-calling",
        " streaming",
        " usf",
        " planning",
        " ultrasafe",
        " ultrasafe ai",
        " usf-agents"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b593ef3ac85f76c97f3c65a9b902bafa57d35595b46cbf8fc91ae57e83cba28d",
                "md5": "05e6da193a9070bf08cfe5e459754b2a",
                "sha256": "21c25ce948e5b8e70f03f4ac7b5ba00949473bf2e11bc4b3d210a607cc71b003"
            },
            "downloads": -1,
            "filename": "usf_agents-2.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "05e6da193a9070bf08cfe5e459754b2a",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 47230,
            "upload_time": "2025-08-29T05:48:40",
            "upload_time_iso_8601": "2025-08-29T05:48:40.905148Z",
            "url": "https://files.pythonhosted.org/packages/b5/93/ef3ac85f76c97f3c65a9b902bafa57d35595b46cbf8fc91ae57e83cba28d/usf_agents-2.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b718e79c05f9f17f659f67ecfc59cbb3f95827c9dec9b017e0d7f0be702be6b3",
                "md5": "c83f095d051836a36d7991619d6b3f5a",
                "sha256": "d63cde4e3252989101735f7e849b57508cc4a6d31548facbf8171bf235114228"
            },
            "downloads": -1,
            "filename": "usf_agents-2.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "c83f095d051836a36d7991619d6b3f5a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 64589,
            "upload_time": "2025-08-29T05:48:42",
            "upload_time_iso_8601": "2025-08-29T05:48:42.718413Z",
            "url": "https://files.pythonhosted.org/packages/b7/18/e79c05f9f17f659f67ecfc59cbb3f95827c9dec9b017e0d7f0be702be6b3/usf_agents-2.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-29 05:48:42",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "UltraSafeAI",
    "github_project": "usf-agents-python",
    "github_not_found": true,
    "lcname": "usf-agents"
}
        
Elapsed time: 0.77284s