> For the complete documentation index, see [llms.txt](https://docs.navigaglobal.com/content-agent/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.navigaglobal.com/content-agent/1.12.0/developer/develop-with-content-agent.md).

# Develop with Content Agent

### Getting started

Content Agent gives you methods to use in your plugin such as `opencontent` to be able to do search/suggest requests from OpenContent by passing your search query for example!

Content Agent register it's own methods with [Dashboard Actions](https://docs.infomaker.io/dashboard-plugin/agent/actions)

You can use any of these actions in your plugin.

### Available actions

| ID                                    | Descriptions                                                                                           |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| com.naviga.content-agent:getProviders | An action to return all available provider names (from config)                                         |
| com.naviga.content-agent:getInstance  | An action returns the instance of Content Agent with Opencontent, Querystreamer and Infocaster methods |

#### With getInstance action you will get a fully powerful class that has three main instances:

* **opencontent**:
  * search -  *promise request.*
  * request -  *promise request*
  * suggest -  *promise request*
* **querystreamer**
  * activeStreams
  * createStream
  * deleteStream
* **infocaster**
  * activeSubscriptions
  * broadcast
  * subscribe
  * unsubscribe

{% hint style="info" %}
The search, request and suggest actions are basically splitted methods from OpenContent instance
{% endhint %}

### An example to how to get Content Agent instance

In your plugin you can import **useAction** from Dashboard, so you can "import" Content Agent actions to your plugin.

{% tabs %}
{% tab title="Hook component" %}

```jsx
import { useAction } from 'Dashboard'
import { useRef, useState, useEffect } from 'react'

const MyAwesomeComponent = props => {
    const CA = useRef()

    const [ready, setReady] = useState(false)
    
    useEffect(() => {
        const getInstance = useAction('com.naviga.content-agent:getInstance')
        const Instance = getInstance()
        
        CA.current = new Instance({
            onStatusChange: caReady => {
                setReady(caReady)
            }
        })
    }, [])
}
```

{% endtab %}

{% tab title="Class component" %}

```jsx
import { Component } from 'react'
import { useAction } from 'Dashboard'

class MyAwesomeComponent extends Component {
    constructor(props) {
        super(props)
        
        this.CA = null
        
        this.state = {
            ready: false
        }
    }
    
    componentDidMount() {
        const getInstance = useAction('com.naviga.content-agent:getInstance')
        const Instance = getInstance()
        
        this.CA = new Instance({
            onStatusChange: caReady => {
                this.setState({
                    ready: caReady
                })
            }
        })
    }
}
```

{% endtab %}
{% endtabs %}

Here we used `com.naviga.content-agent:getInstance` action to get and initiate our CA instance, and listening on CA status changes with `onStatusChange`&#x20;

### Open Content

To access Open Content you call `CA.opencontent()` with the name of content provider you want to use (from config).

Access to `search` and `suggest` is simplified by two helper functions, but any OC REST API endpoint can be reached using the `request` function. The functions returns promises.

[Open Content API Documentation](http://xlibris.demo.oc.imit.infomaker.io:8080/opencontent/apidocs/)

#### Search

```javascript
const searchQuery = {
    q: "*:*"
}

CA.opencontent('im-demo').search(searchQuery).then(searchResult => {
    console.log(searchResult)
})
```

#### Suggest

```javascript
const suggestQuery = {
    'field': ['Authors'],
    'incompleteWord': ['P'],
    'type': 'ngram'
}

CA.opencontent('im-demo').suggest(suggestQuery).then(suggestResult => {
    console.log(suggestResult)
})
```

#### Generic OC API request

```javascript
const params = {
    'endpoint': 'eventlog',
    'method': 'GET',
    'qs': {
      'event' : -1
    }
}

CA.opencontent('im-demo').request(params).then(eventlogRes => {
    console.log(eventlogRes)
})
```

{% hint style="info" %}
search, suggest and request actions works the same as accessing them from CA.opencontent

by passing the provider as first argument and the request params as a second argument
{% endhint %}

### QueryStreamer

To handle streams in QueryStreamer you call `CA.querystreamer()` with the name of content provider you want to use (from config).

createStream and deleteStream is enabled on this instance.

[QueryStreamer API Documentation](https://querystreamer.lcc.infomaker.io/documentation)

[ElasticSearch Query Format Documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/_introducing_the_query_language.html)

#### Create stream

When calling create stream, pass a request object and a callback function as parameters. This will return a promise that resolves with a stream ID. New events will land in the callback function you provided.

```javascript
const BUNDLE = "@plugin_bundle";
const VERSION = "@plugin_version";

const onStreamEvent = (event) => {
    const ocEvent = event.data.payload.result
    const noLongerMatching = event.data.payload.parameters.noLongerMatchingQuery
}

const req = {
    query : {
        query_string: {
            query : '*:*'
        }
    },
    config : {
        'notifyOnNoLongerMatchingQuery' : true
    },
    meta : {
        origin : {  // Add bundle and version to meta.origin. This helps when troubleshooting.
            bundle : BUNDLE,
            version : VERSION
        }
    }
}
const querystreamer = this.lcc.querystreamer('im-demo')
const updateStreamId = res => {
    // This will be called when a stream resumes after a disconnect as well
    // as initially with a temporary streamId in order to be able to clean up
    // if connection is broken before stream is fully setup
    this.streamId = res.streamId
}

return querystreamer.createStream(req, onStreamEvent, updateStreamId).then(res => {
    this.streamId = res.streamId
})
```

#### Delete stream

```javascript
CA.querystreamer('im-demo').deleteStream(STREAM_ID)
```

#### Cleanup

When a stream is no longer needed, **delete** it.

Please don't forget call `deleteStream(streamId)`&#x20;

* If you are creating a stream in a class component you can delete the stream when your component unmounted with `componentWillUnmount`.
* If you are creating a stream in a hook component you can delete the stream when your component unmounted with returning a function with `useEffect`&#x20;
* If you are creating a stream in the Agent you can delete the stream when your Agent close with `close`&#x20;

{% hint style="info" %}
You can handle events easily with querystreamer by passing qsInstance to [QueryEventWrapper](https://github.com/Infomaker/Dashboard-Plugin/wiki/ViewUtil#queryeventwrapper)
{% endhint %}
