> ## Documentation Index
> Fetch the complete documentation index at: https://simplellmfunc.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# Decorators

> API reference for @llm_function, @llm_chat, and @tool

# Decorators API Reference

## @llm\_function

```python theme={null}
from SimpleLLMFunc import llm_function

@llm_function(
    llm_interface: LLM_Interface,
    toolkit: Optional[List[Tool]] = None,
    max_tool_calls: Optional[int] = None,
    system_prompt_template: Optional[str] = None,
    user_prompt_template: Optional[str] = None,
    **llm_kwargs: Any,
)
```

Transforms an async function into an `LLMFunction` callable instance. `await fn(...)` returns the parsed typed result; `fn.stream(...)` yields `ReactOutput`.

For multimodal input, keep the normal Python-function style: explicitly type image parameters as `ImgUrl`, `ImgPath`, or lists/unions containing those types. `ImgUrl` accepts `http(s)` URLs and `data:` URLs; `ImgPath` is encoded as an image data URL at the provider boundary.

### Parameters

| Parameter                | Type                 | Default  | Description                                                        |
| ------------------------ | -------------------- | -------- | ------------------------------------------------------------------ |
| `llm_interface`          | `LLM_Interface`      | required | Model to call                                                      |
| `toolkit`                | `List[Tool] \| None` | `None`   | Tools available to the model                                       |
| `max_tool_calls`         | `int \| None`        | `None`   | Maximum tool calls before forcing final answer. `None` = unlimited |
| `system_prompt_template` | `str \| None`        | `None`   | Override the system prompt template                                |
| `user_prompt_template`   | `str \| None`        | `None`   | Override the user prompt template                                  |
| `**llm_kwargs`           | `Any`                | —        | Forwarded to LLM (temperature, max\_tokens, etc.)                  |

### Special Call-Time Parameters

| Parameter          | Type             | Description                                    |
| ------------------ | ---------------- | ---------------------------------------------- |
| `_template_params` | `Dict[str, Any]` | Template values for docstring `{placeholders}` |
| `_abort_signal`    | `AbortSignal`    | Cancellation signal                            |

### Example

```python theme={null}
from pydantic import BaseModel, Field
from SimpleLLMFunc import llm_function, OpenAICompatible

llm = OpenAICompatible.load_from_json_file("provider.json")["openrouter"]["gpt-4o"]

class Sentiment(BaseModel):
    label: str = Field(description="positive, negative, or neutral")
    score: float = Field(description="confidence 0.0–1.0")

@llm_function(llm_interface=llm)
async def classify(text: str) -> Sentiment:
    """Classify the sentiment of the text."""
    pass

# Usage
result = await classify("I love this!")
print(result)  # Sentiment(label="positive", score=0.95)
```

***

## @llm\_chat

```python theme={null}
from SimpleLLMFunc import llm_chat

@llm_chat(
    llm_interface: LLM_Interface,
    toolkit: Optional[List[Tool]] = None,
    max_tool_calls: Optional[int] = DEFAULT_MAX_TOOL_CALLS,
    stream: bool = False,
    strict_signature: bool = False,
    self_reference: Optional[SelfReference] = None,
    self_reference_key: Optional[str] = None,
    **llm_kwargs: Any,
)
```

Creates an `LLMChat` callable instance. Calling it yields `AsyncGenerator[ReactOutput, None]` and gives SelfRef a stable agent identity.

For multimodal chat input, prefer a single explicit `message: UserChatMessage` argument. `UserChatMessage` is OpenAI Chat Completions-compatible and can contain text and `image_url` content parts.

### Parameters

| Parameter            | Type                    | Default           | Description                            |
| -------------------- | ----------------------- | ----------------- | -------------------------------------- |
| `llm_interface`      | `LLM_Interface`         | required          | Model to call                          |
| `toolkit`            | `List[Tool] \| None`    | `None`            | Available tools                        |
| `max_tool_calls`     | `int \| None`           | framework default | Tool call limit per invocation         |
| `stream`             | `bool`                  | `False`           | Enable streaming chunks                |
| `strict_signature`   | `bool`                  | `False`           | Enforce strict parameter validation    |
| `self_reference`     | `SelfReference \| None` | `None`            | Explicit SelfReference backend         |
| `self_reference_key` | `str \| None`           | `None`            | Auto-create SelfReference for this key |
| `**llm_kwargs`       | `Any`                   | —                 | Forwarded to LLM                       |

### Special Call-Time Parameters

| Parameter           | Type             | Description                             |
| ------------------- | ---------------- | --------------------------------------- |
| `_template_params`  | `Dict[str, Any]` | Template values                         |
| `_abort_signal`     | `AbortSignal`    | Cancellation signal                     |
| `_too_long_to_file` | `bool`           | Truncate long tool results to temp file |

### History Parameter

The function must have a parameter named `history` or `chat_history` (type: `list | None`). The framework uses it to carry conversation state.

### Example

```python theme={null}
from SimpleLLMFunc import llm_chat, tool

@tool
async def search(query: str) -> str:
    """Search for information."""
    return f"Result for: {query}"

@llm_chat(llm_interface=llm, toolkit=[search], stream=True)
async def agent(message: str, history: list | None = None):
    """A helpful research assistant."""
    pass

# Usage
history = []
async for output in agent("What is SimpleLLMFunc?", history):
    if is_response_yield(output):
        print(output.response)
        history = output.messages
```

### Multimodal Chat Example

```python theme={null}
from SimpleLLMFunc import llm_chat
from SimpleLLMFunc.type import UserChatMessage, ImgUrl

@llm_chat(llm_interface=llm)
async def vision_agent(message: UserChatMessage, history: list | None = None):
    """Answer questions about user-provided images."""
    pass

async for output in vision_agent(
    UserChatMessage.multimodal(
        "What is in this image?",
        ImgUrl("https://example.com/cat.jpg", detail="high"),
    ),
    history=[],
):
    ...
```

***

## @tool

```python theme={null}
from SimpleLLMFunc import tool

@tool(
    name: Optional[str] = None,
    description: Optional[str] = None,
    best_practices: Optional[Sequence[str]] = None,
    prompt_injection_builder: Optional[Callable] = None,
    too_long_to_file: bool = False,
)
```

Registers an async function as a tool callable by the LLM. Can be used with or without arguments.

### Parameters

| Parameter                  | Type                    | Default        | Description                             |
| -------------------------- | ----------------------- | -------------- | --------------------------------------- |
| `name`                     | `str \| None`           | function name  | Override tool name                      |
| `description`              | `str \| None`           | from docstring | Override tool description               |
| `best_practices`           | `Sequence[str] \| None` | from docstring | Override best practices list            |
| `prompt_injection_builder` | `Callable \| None`      | `None`         | Dynamic system prompt injection         |
| `too_long_to_file`         | `bool`                  | `False`        | Write results > 20k tokens to temp file |

### Requirements

* Decorated function **must** be `async def`
* Docstring should include `Args`, `Returns`, and `Best Practices` sections
* Parameter types become the tool's JSON schema

### Example

```python theme={null}
from SimpleLLMFunc import tool

@tool
async def calculate(expression: str) -> float:
    """
    Evaluate a math expression.

    Args:
        expression: Python math expression (e.g., "2 ** 10").

    Returns:
        Numeric result.

    Best Practices:
        - Use Python syntax.
        - Keep expressions simple.
    """
    return float(eval(expression))

# Used without parentheses (simple form)
@tool
async def simple_tool(x: str) -> str:
    """Do something."""
    return x.upper()
```

***

## Tool Class

```python theme={null}
from SimpleLLMFunc import Tool

tool_instance = Tool(
    name: str,
    description: str,
    func: Callable[..., Awaitable[Any]],
    best_practices: Optional[Sequence[str]] = None,
    prompt_injection_builder: Optional[Callable] = None,
    too_long_to_file: bool = False,
)
```

For programmatic tool creation without the decorator.

### Methods

| Method                                    | Returns       | Description                       |
| ----------------------------------------- | ------------- | --------------------------------- |
| `.tool_spec()`                            | `Dict`        | Tool specification dict           |
| `.to_openai_tool()`                       | `Dict`        | OpenAI-format tool definition     |
| `.serialize_tools(tools)`                 | `List[Dict]`  | Class method: serialize tool list |
| `.build_system_prompt_injection(context)` | `str \| None` | Dynamic prompt injection          |

### Properties

| Property       | Type              | Description                   |
| -------------- | ----------------- | ----------------------------- |
| `.name`        | `str`             | Tool name                     |
| `.description` | `str`             | Tool description              |
| `.parameters`  | `List[Parameter]` | Extracted parameters          |
| `.func`        | `Callable`        | The underlying async function |
