# Add a New Block via Composition API

## Step 1: Import Necessary Components

Import the necessary components

{% code fullWidth="false" %}

```typescript
import { OAIBaseComponent, type OmniComponentFormat, WorkerContext, OmniComponentMacroTypes } from "./path_to_file"
```

{% endcode %}

## Step 2: Create a New Component Instance

Instantiate the ComponentComposer and initialize your component by defining its namespace and operationId using the .create(displayNamespace, displayOperationId) method.

Set the namespace to `const NS_OMNI`

<pre class="language-typescript"><code class="lang-typescript">const NS_OMNI = 'your_namespace'
<strong>let component = OAIBaseComponent.create(NS_OMNI, 'your_operationId')
</strong></code></pre>

## Step 3: Define Component Characteristics

Further define the characteristics of your component using provided methods. You can set the title, description, method, and category.

```typescript
component
    .fromScratch()
    .set('description', 'Your description')
    .set('title', 'Your title')
    .set('category', 'Your category')
    .setMethod('Your Method')
    .setMeta({
        source: {
            summary: 'A standard text input component with built-in URL fetching, enabling it to be connected to File (Image/Audio/Document) sockets',
            authors: ['Mercenaries.ai Team'],
            links: {
                'Mercenaries.ai': 'https://mercenaries.ai'
            }
        }
    })
```

Instead of using the `fromScratch()` method, you can also utilize the `fromJSON()` method with a valid `Partial<OmniComponentFormat>` JSON. This must include both the `displayNamespace/operationID` and `apiNamespace/operationId`.

```typescript
const partialComponentFormat: Partial < OmniComponentFormat > = {
    displayNamespace: 'your_display_namespace',
    displayOperationId: 'your_display_operationId',
    apiNamespace: 'your_api_namespace',
    apiOperationId: 'your_api_operationId',
    // other properties can be added as needed
};
component.fromJSON(partialComponentFormat)
```

## **Step 4: Create and Add Inputs and Outputs**

For inputs and outputs, you'll first create an `IOComposer` using the `.createInput(name, type, customSocket)` or `.createOutput(name, type, customSocket)` methods. You can further define their properties, including setting up controls which can be automatically selected or overridden.

Inputs always have controls associated with them, and they can be defined directly within the input creation process. Here's an example of defining an input with a control:

```typescript
const input = component.addInput(
  component.createInput('input_name', 'input_type', 'input_x-type')
    .set('title', 'Input title')
    .set('description', 'Input description')
    .setDefault('default value')
    .setConstraints(min value, max value)
    .setChoice([])
    .setRequired(true)
    .allowMultiple(true) // enable an input to accept multiple connections. 
    .setControl({
        controlType: 'alpine control type' 
      }) // Override the automatically selected control
    .toOmniIO()
);
```

**Note:**

When using `.allowMultiple()` in conjunction with `{ array: true }`, the input array is flattened into a single array:

```typescript
component.createInput('input_name', 'input_type', 'input_x-type', {array:true})
```

You can define which characters are used for joining (or separating on input) an array (default is \n) via a custom setting (specific to the Text Socket):

```typescript
{array: true, customSettings: {array_separator = '-------' }};
```

***

Alternatively, you can also define inputs and outputs in an array:

```typescript
const inputs = [
  { name: 'text', type: 'string', description: 'A string', customSocket: 'text' },
  // More input definitions...
  { name: 'usSocialSecurityNumber', type: 'boolean', default: true }
];

inputs.forEach(({ name, type, customSocket, description, default: defaultValue }) => {
  component.addInput(
    component.createInput(name, type, customSocket)
      .set('description', description)
      .setDefault(defaultValue)
      .toOmniIO()
  );
});
```

You also have the option to directly write the JSON if that's your preference.

## Step 5: Create and Add Controls (Optional)

Controls are created using the `ControlComposer` and are added similarly to inputs/outputs.

<pre class="language-typescript"><code class="lang-typescript">let controlComposer = component.createControl('controlName')

component
  .addControl(
    controlComposer
      .setRequired(true)
      .setControlType('alpineControlType')
<strong>      .toOmniControl()
</strong>  );
</code></pre>

Or

```typescript
component.addControl(
  component
    .createControl("controlName")
    .setRequired(true)
    .setControlType("alpineControlType")
    .toOmniControl()
);
```

## Step 6: Define Execution Macro

You can define the behavior of your component using a macro. In this case, the `OmniComponentMacroTypes.EXEC` macro type is used.

```typescript
component.setMacro(OmniComponentMacroTypes.EXEC, (payload: any, ctx: WorkerContext) => {
  // define your function here
})
```

## Step 8: Export the Component

Finally, convert the component to JSON and export it.

```typescript
const YourComponent = component.toJSON() 
export default YourComponent
```

## Step 9: Add the Component to App Blocks

```javascript
app.blocks.addBlock(component)
```

**Note:** extensions don’t need to call `addBlock`. they just need to export the `createComponent` function.

## Optional Settings:

### Composing Patches

To compose a patch with a valid `OmniComponentPatch`, the same format applies:

```javascript
let patch= OAIBaseComponent
  .createPatch(NS_ONMI, "text_replace")
  .fromComponent(apiNamespace, apiOperationId)
  ....
  .toJSON() //<-- OmnicomponentPatch

app.blocks.addPatch(patch)
```

### Dependencies

Use `.dependsOn(string[])` to specify dependencies, indicating if a block relies on other blocks (for instance, when using `runblock` internally). For example:

{% code overflow="wrap" %}

```typescript
component.dependsOn(['automatic1111.interrogateapi_sdapi_v1_interrogate_post', 'automatic1111.simpleImage2Image']);
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://omnitool-ai.gitbook.io/omnitool/advanced/create-new-blocks/add-a-new-block-via-composition-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
