GraphQL AI Text Mutations

PagibleAI adds authenticated GraphQL mutations for generating text, refining structured page content, describing stored files, transcribing audio and translating text. The available operations depend on the configured AI providers and the current user’s CMS permissions.

See PagibleAI GraphQL API for authentication and JSON scalar handling, GraphQL Pages for conflict-safe drafts, and GraphQL Files for stored file references and multipart uploads.

Generate text with write

write generates plain text from a prompt. You can add context and up to ten stored file UUIDs as reference material.

mutation WriteText(
  $prompt: String!
  $context: String
  $files: [String!]
) {
  write(prompt: $prompt, context: $context, files: $files)
}
{
  "prompt": "Write a concise product description for wireless headphones.",
  "context": "Audience: commuters. Tone: direct and practical.",
  "files": ["018f2567-8508-7a62-9309-41708fbfe5fa"]
}

write arguments

Argument
Type
Limit
prompt
String!
Required, at most 2,000 characters
context
String
At most 30,000 characters
files
[String!]
At most 10 file UUIDs; each at most 36 characters

The mutation returns String. Referenced files also require file:view permission.

Refine structured content

refine rewrites existing CMS content and validates the result against the selected content schema. Encode the original content as a JSON string for the MLL JSON scalar, describe the desired changes, and use pagetype when the page type has a specialized schema.

mutation RefineContent(
  $prompt: String!
  $content: JSON!
  $type: String
  $context: String
  $lang: String
  $pagetype: String
) {
  refine(
    prompt: $prompt
    content: $content
    type: $type
    context: $context
    lang: $lang
    pagetype: $pagetype
  )
}
{
  "prompt": "Make the introduction clearer and add a specific call to action.",
  "content": "[{\"id\":\"intro\",\"type\":\"text\",\"group\":\"main\",\"data\":{\"text\":\"Take a look at our services.\"}}]",
  "type": "content",
  "context": "B2B consulting landing page",
  "lang": "en",
  "pagetype": "page"
}

refine arguments

Argument
Type
Limit
prompt
String!
Required, at most 2,000 characters
content
JSON!
JSON-encoded existing CMS content
type
String
Schema group, at most 255 characters
context
String
At most 30,000 characters
lang
String
Output language, at most 10 characters
pagetype
String
Page type, at most 255 characters

The mutation returns validated JSON as an encoded string. Parse it before review, then pass the encoded result to savePage when you want to create a draft. refine does not save or publish the page itself.

{
  "data": {
    "refine": "[{\"id\":\"intro\",\"type\":\"text\",\"group\":\"main\",\"data\":{\"text\":\"Choose the service that fits your next project, then book a consultation.\"}}]"
  }
}

Save refined content as a page draft

mutation SaveRefinedPage(
  $page: ID!
  $latestId: ID!
  $content: JSON!
) {
  savePage(
    id: $page
    latestId: $latestId
    input: {content: $content}
  ) {
    id
    changed
    latest { id published }
  }
}
const refined = JSON.parse(refineResult.data.refine);

// Validate and render a preview before saving.
const saveVariables = {
  page: page.id,
  latestId: page.latest.id,
  content: JSON.stringify(refined),
};

const saveResult = await runGraphql(SAVE_REFINED_PAGE, saveVariables);

if (saveResult.data.savePage.changed) {
  // Re-read the page and review the conflict before continuing.
}

// savePage created a draft. It did not publish the page.

Treat generated content as untrusted editorial input: validate it against the active theme schema, preview it, inspect links and factual claims, and only then save the draft. Publishing remains a separate operation.

Describe a stored file

mutation DescribeFile($file: String!, $lang: String) {
  describe(file: $file, lang: $lang)
}
{
  "file": "018f2567-8508-7a62-9309-41708fbfe5fa",
  "lang": "en"
}
{
  "data": {
    "describe": "A side view of a compact electric bicycle beside a city café."
  }
}

file is a stored file UUID of at most 36 characters; lang is at most 5 characters. The mutation returns a text description and requires both file:describe and file:view.

Transcribe uploaded audio

transcribe accepts an Upload! using the GraphQL multipart request specification. It returns the transcription through the JSON scalar as a JSON-encoded string.

mutation TranscribeAudio($file: Upload!) {
  transcribe(file: $file)
}
{
  "data": {
    "transcribe": "{\"en\":\"Welcome to the product briefing.\"}"
  }
}

The upload must comply with the configured file-size and MIME policies. The caller needs audio:transcribe permission.

Translate text

mutation TranslateText(
  $texts: [String!]!
  $to: String!
  $from: String
  $context: String
) {
  translate(texts: $texts, to: $to, from: $from, context: $context)
}
{
  "texts": [
    "Welcome to our website.",
    "Compare our service plans."
  ],
  "to": "de",
  "from": "en",
  "context": "Formal business website"
}
{
  "data": {
    "translate": [
      "Willkommen auf unserer Website.",
      "Vergleichen Sie unsere Servicepakete."
    ]
  }
}

translate arguments

Argument
Type
Limit
texts
[String!]!
1 to 50 texts; each at most 10,000 characters
to
String!
Target language code, at most 5 characters
from
String
Source language code, at most 5 characters
context
String
At most 1,000 characters

The result is [String!]! in the same order as the input. The caller needs text:translate permission.

Errors and provider configuration

AI calls can fail because of validation, permissions, provider configuration, rate limits or upstream service errors. Check the GraphQL errors array and keep provider credentials in server-side configuration. These mutations return generated data; they do not publish CMS content automatically.

{
  "errors": [
    {
      "message": "AI provider request failed",
      "path": ["write"]
    }
  ],
  "data": {
    "write": null
  }
}

Troubleshoot AI text mutations

Common AI text problems

Symptom
Likely cause
Resolution
Prompt must not be empty
The prompt is blank
Send a specific instruction within the documented limit
Insufficient permissions
The mutation or a referenced file is not allowed
Check the AI capability and file:view
Invalid JSON value
refine content was sent as a native array
Encode the content once for the JSON scalar
Content exceeds a limit
Input bytes or nesting are above configured AI limits
Reduce the content or split the operation
Invalid content in refine response
The provider output failed schema validation
Clarify the prompt or use a compatible model
Provider request failed
Credentials, model, quota or upstream service failed
Check server-side AI configuration and logs
Client timed out
The client timeout is shorter than the AI operation
Align it with the configured CMS AI timeout
Public page did not change
Generated output was returned but not saved and published
Review, savePage, then publish separately