---
title: "Shared JSON controller"
manual: "AI Assistant"
version: "2.0"
permalink: "https://docs.typo3.org/permalink/madj2k/t3-ai-assistant:shared-json-controller@2.0"
source: "Developers/Architecture/JsonController.rst"
rendered: "2026-11-01T13:06:29+00:00"
---

# Shared JSON controller {#shared-json-controller}

The AI Assistant JSON API is a transport adapter for complete Assistant turns.
It does not implement a second pipeline. The controller creates an
`AssistantRequest` and delegates execution to the Core `Orchestrator`.

## Architecture {#architecture}

```text
Native search middleware       JsonController
         |                            |
         +-------- AssistantRequest +
                                  |
                          Orchestrator->handle()
                                  |
                          AssistantResponse
```

The native middleware returns a redirect. The JSON controller returns the
Assistant response as JSON. Both use the same Assistant profile and pipeline.

## Controller action {#controller-action}

The action is registered as `JsonController->assistantAction` in the base
`ai_assistant` extension and exposed by page type `1790831371`. Its request
parameters use the normal chat namespace:

```text
tx_aiassistant_chat[query]
tx_aiassistant_chat[startTimestamp]
tx_aiassistant_chat[assistantProfile]
tx_aiassistant_chat[chatIdentifier]
tx_aiassistant_chat[settingsJson]
tx_aiassistant_chat[requestToken]
tx_aiassistant_chat[userLanguage]
tx_aiassistant_chat[directInteraction]
```

The controller does not accept search result rows. The Summary flow uses the
existing Assistant SSE chat instead. Its canonical payload is placed in
`settings.search.capturedResults` by the Vue payload-builder component before
the chat stream starts.

## Assistant response {#assistant-response}

The JSON response follows the Core `AssistantResponse` shape and only adds
the request identity used by the frontend:

```json
{
    "answer": "",
    "originalQuery": "Original user query",
    "currentQuery": "Optimized Query",
    "debug": [],
    "assistantProfile": 1001,
    "chatIdentifier": "search-123"
}
```

For a query-optimization profile without an Answer Generator, `answer` may
be empty. The optimized query is then available at:

```javascript
response.currentQuery
```

## Security {#security}

The controller is not an open Assistant runner. Before executing the
Orchestrator it verifies:

-   the Assistant profile against the active site's
    `aiAssistant.allowedAssistantProfiles` setting;
-   the signed frontend token;
-   the site, Assistant profile and chat identifier bound into that token;

The token is created by `FrontendRequestTokenService` and rendered into the
Premium custom element. It is signed with TYPO3's encryption key and contains
an expiration timestamp. The browser may see the token; its purpose is
integrity and capability validation, not secrecy.

## Extending the controller {#extending-the-controller}

New JSON operations should reuse the existing controller boundary and Core
Orchestrator. Do not create a second pipeline in Premium. If an operation needs
additional input, validate it before building the `AssistantRequest` and keep
the response compatible with `AssistantResponse`.
