> ## Documentation Index
> Fetch the complete documentation index at: https://extended-openai-conversation.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Composite Functions

> Chain multiple function types together

Composite functions execute a sequence of different function types, passing data between them. They're ideal for complex workflows that require multiple steps with different capabilities.

## Configuration

```yaml theme={null}
function:
  type: composite
  sequence:
    - type: function_type_1
      # Configuration for first function
      response_variable: result1
    - type: function_type_2
      # Configuration for second function (can use {{ result1 }})
```

<ParamField path="sequence" type="array" required>
  List of functions to execute in order. Each can be any function type.
</ParamField>

<ParamField path="response_variable" type="string">
  Variable name to store this step's result for use in subsequent steps
</ParamField>

## Data Flow

Data flows between sequence steps using `response_variable`:

<Steps>
  <Step title="Step 1 executes">
    First function runs and produces a result

    ```yaml theme={null}
    - type: rest
      resource: https://api.example.com/data
      response_variable: api_data
    ```
  </Step>

  <Step title="Result stored">
    Result is stored in the variable name specified by `response_variable`
  </Step>

  <Step title="Step 2 accesses data">
    Subsequent steps can use the variable in templates

    ```yaml theme={null}
    - type: template
      value_template: "Received: {{ api_data.count }} items"
    ```
  </Step>

  <Step title="Final result">
    The last step's output becomes the function's final result
  </Step>
</Steps>

## Use Cases

<CardGroup cols={2}>
  <Card title="Data Processing" icon="gears">
    Fetch raw data and format it for presentation
  </Card>

  <Card title="Multi-step Workflows" icon="diagram-project">
    Execute complex sequences requiring different function types
  </Card>

  <Card title="Service + Template" icon="code">
    Call services and format their responses
  </Card>

  <Card title="Conditional Logic" icon="code-branch">
    Use templates to process results conditionally
  </Card>
</CardGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Name variables clearly">
    Use descriptive names for `response_variable`:

    ```yaml theme={null}
    response_variable: weather_data  # Good
    response_variable: result        # Too generic
    response_variable: r1            # Not descriptive
    ```
  </Accordion>

  <Accordion title="Keep sequences focused">
    Each composite function should accomplish one logical task. If you need many steps, consider breaking into multiple functions.

    ✅ Good: 2-4 steps for a single purpose

    ❌ Bad: 10+ steps doing unrelated things
  </Accordion>

  <Accordion title="Handle errors">
    Add error handling in templates:

    ```jinja2 theme={null}
    {% if api_data is defined and api_data.success %}
      {{ api_data.result }}
    {% else %}
      Error: Could not fetch data
    {% endif %}
    ```
  </Accordion>

  <Accordion title="Debug step by step">
    Test each step individually before combining:

    1. Create individual functions for each step
    2. Verify each works correctly
    3. Combine into composite function
    4. Test the complete sequence
  </Accordion>
</AccordionGroup>

## Common Patterns

### Pattern 1: API + Format

```yaml theme={null}
sequence:
  - type: rest
    resource: https://api.example.com/data
    response_variable: raw_data
  - type: template
    value_template: "{{ raw_data | format_nicely }}"
```

### Pattern 2: Service + Extract

```yaml theme={null}
sequence:
  - type: script
    sequence:
      - service: domain.service
        response_variable: service_result
  - type: template
    value_template: "{{ service_result.important_field }}"
```

### Pattern 3: Multi-source Aggregation

```yaml theme={null}
sequence:
  - type: rest
    resource: https://api1.example.com
    response_variable: data1
  - type: rest
    resource: https://api2.example.com
    response_variable: data2
  - type: template
    value_template: >-
      Combined data:
      Source 1: {{ data1.value }}
      Source 2: {{ data2.value }}
```

### Pattern 4: Scrape + Process

```yaml theme={null}
sequence:
  - type: scrape
    resource: https://example.com
    response_variable: scraped
    sensor:
      - name: price
        select: ".price"
  - type: template
    value_template: >-
      {% set clean_price = scraped.price | replace('$', '') | float %}
      Price: ${{ "%.2f" | format(clean_price) }}
```

## Debugging

Enable detailed logging:

```yaml theme={null}
logger:
  logs:
    custom_components.extended_openai_conversation: debug
```

Logs will show:

* Each step's input parameters
* Each step's output result
* Variable assignments
* Template rendering

## Examples

### Search and Play Music

Search for music, then play the first result:

```yaml theme={null}
- spec:
    name: search_music
    description: Use this function to search music
    parameters:
      type: object
      properties:
        query:
          type: string
          description: The search query
      required:
      - query
  function:
    type: composite
    sequence:
    - type: script
      sequence:
      - service: ytube_music_player.search
        data:
          entity_id: media_player.ytube_music_player
          query: "{{ query }}"
    - type: template
      value_template: >-
        media_content_type,media_content_id,title
        {% for media in state_attr('sensor.ytube_music_player_extra', 'search') -%}
          {{media.type}},{{media.id}},{{media.title}}
        {% endfor%}
```

<Frame>
  <img width="300" alt="Music Search" src="https://github.com/jekalmin/extended_openai_conversation/assets/2917984/648efef8-40d1-45d2-b3f9-9bac4a36c517" />
</Frame>

### Get History with Formatting

Combine native `get_history` with template formatting:

```yaml theme={null}
- spec:
    name: get_history
    description: Retrieve historical data of specified entities.
    parameters:
      type: object
      properties:
        entity_ids:
          type: array
          items:
            type: string
            description: The entity id to filter.
        start_time:
          type: string
          description: Start of the history period in "%Y-%m-%dT%H:%M:%S%z".
        end_time:
          type: string
          description: End of the history period in "%Y-%m-%dT%H:%M:%S%z".
      required:
      - entity_ids
  function:
    type: composite
    sequence:
      - type: native
        name: get_history
        response_variable: history_result
      - type: template
        value_template: >-
          {% set ns = namespace(result = [], list = []) %}
          {% for item_list in history_result %}
              {% set ns.list = [] %}
              {% for item in item_list %}
                  {% set last_changed = item.last_changed | as_timestamp | timestamp_local if item.last_changed else None %}
                  {% set new_item = dict(item, last_changed=last_changed) %}
                  {% set ns.list = ns.list + [new_item] %}
              {% endfor %}
              {% set ns.result = ns.result + [ns.list] %}
          {% endfor %}
          {{ ns.result }}
```

### Fetch and Process External Data

Get data from API and format it:

```yaml theme={null}
- spec:
    name: get_weather_detailed
    description: Get detailed weather information
    parameters:
      type: object
      properties:
        city:
          type: string
          description: City name
      required:
      - city
  function:
    type: composite
    sequence:
      - type: rest
        resource: "https://wttr.in/{{ city }}?format=j1"
        response_variable: weather_data
      - type: template
        value_template: >-
          Weather in {{ city }}:
          Current: {{ weather_data.current_condition[0].temp_C }}°C, {{ weather_data.current_condition[0].weatherDesc[0].value }}
          Humidity: {{ weather_data.current_condition[0].humidity }}%
          Wind: {{ weather_data.current_condition[0].windspeedKmph }} km/h

          3-Day Forecast:
          {% for day in weather_data.weather[:3] %}
          {{ day.date }}: {{ day.mintempC }}-{{ day.maxtempC }}°C
          {% endfor %}
```

## Next Steps

<CardGroup cols={3}>
  <Card title="Native Functions" icon="microchip" href="/functions/native">
    Built-in functions
  </Card>

  <Card title="Template Functions" icon="brackets-curly" href="/functions/template">
    Data formatting
  </Card>

  <Card title="Script Functions" icon="scroll" href="/functions/script">
    Service sequences
  </Card>
</CardGroup>
