Aviator API Reference

This reference details the Aviator Worfklow API. It provides background information and best practices for working with Aviator workflows.

Applies to: On-premises only. This API is not compatible with SaaS deployments. When invoked from a SaaS tenant, the on-premises Aviator Workflow API fails because it produces output that is incompatible with the GenAI middleware.

Entry Points

TDConnection.Aviator()

Main entry point for creating Aviator workflows.

Copy code
const aviator = TDConnection.Aviator()

// Check if enabled (license + feature flag)
if (aviator.isEnabled()) {
  // Start building a prompt
  const response = await aviator.prompt().instructions('...').send()
}

Methods:

  • .prompt() → Returns PromptBuilder
  • .buildFormat() → Returns OutputFormatBuilder
  • .isEnabled() → Returns boolean (checks license availability)
  • .setDefaultPersona(text) → Sets default persona for all prompts
  • .setDefaultLanguage(lang) → Sets default language
  • .showSuggestionsModal(data, options) → Show modal with custom data

.isEnabled(): boolean

Critical for Workflow Scripts - Check if Aviator is licensed and available before using AI features.

Copy code
// Always check before using Aviator features
if (!TDConnection.Aviator().isEnabled()) {
  MsgBox('Aviator is not available. Please check your license.')
  return
}

// Safe to use Aviator
const response = await TDConnection.Aviator()
  .prompt()
  .instructions('Generate test cases')
  .send()

Returns:true if Aviator is licensed and available, false otherwise.

Best Practice: Always wrap Aviator operations with an isEnabled() check to gracefully handle unlicensed environments.

TDConnection.Utils

Utility functions for text processing.

Copy code
// Strip HTML tags
TDConnection.Utils.stripHtml('<p>Hello <b>World</b></p>') // 'Hello World'

// Remove special characters
TDConnection.Utils.removeSpecialChars('Hello! @World#123') // 'Hello World123'

// Normalize whitespace
TDConnection.Utils.normalizeWhitespace('Hello  \n World') // 'Hello World'

// Get MIME type from filename
TDConnection.Utils.getMimeType('video.mp4') // 'video/mp4'

// Clean text for AI prompt (combines stripHtml + normalizeWhitespace)
TDConnection.Utils.cleanForPrompt('<p>Hello  World</p>') // 'Hello World'

// Truncate text
TDConnection.Utils.truncate('Long text here', 8) // 'Long...'

PromptBuilder API

Overview

PromptBuilder provides a fluent interface for constructing AI prompts.

Methods

.persona(text: string): this

Define the AI's role and expertise.

Copy code
.persona('You are a senior QA engineer with 10 years of experience in API testing')

.instructions(text: string): this

Add instructions. Chainable - call multiple times for clarity.

Copy code
.instructions('Generate test cases for this requirement')
.instructions('Include both positive and negative scenarios')
.instructions('Add step-by-step test procedures')

.context(data: object | string): this

Provide context data for the AI.

Copy code
// Object context
.context({
  requirement: 'User Login',
  description: 'Users must authenticate with username/password',
  priority: 'High'
})

// String context (wrapped as {content: '...'})
.context(req.Field('RQ_REQ_COMMENT').Value)

.addContext(key: string, value: any): this

Add a single context key-value pair.

Copy code
.addContext('module', 'Authentication')
.addContext('riskLevel', 'Critical')

.format(schema: OutputFormat): this

Set the expected output structure.

Copy code
.format(TDConnection.Formats.TestCases)  // Predefined
.format(customFormat)                     // Custom

.language(lang: string): this

Set the response language.

Copy code
.language('Spanish')
.language(TDConnection.GetPreferredLanguage())

.maxResults(count: number): this

Limit the number of results.

Copy code
.maxResults(5)  // Generate exactly 5 items

.useEntityChildren(): this

Add instruction to consider child entities when generating content.

Copy code
// When generating tests, consider sub-requirements for fuller coverage
.useEntityChildren()

This adds an instruction to the AI to consider hierarchical relationships. When combined with context data, it helps generate more comprehensive results.

Use Case: When generating test cases from a parent requirement, enable this to signal that sub-requirements should be considered for coverage.

Copy code
// Provide sub-requirements as context and enable the flag
const subReqs = getSubRequirements(parentReqId)
await TDConnection.Aviator()
  .prompt()
  .instructions('Generate test cases covering all requirements')
  .context({ 
    requirement: parentReq,
    subRequirements: subReqs  // Provide the data
  })
  .useEntityChildren()        // Signal to AI to use hierarchical context
  .format(TDConnection.Formats.TestCases)
  .send()

.avoidDuplication(): this

Add instruction to avoid duplicating existing content.

Copy code
// When generating new tests, avoid duplicating existing linked tests
.avoidDuplication()

This adds an instruction to the AI to check for and avoid duplicating existing items. When combined with context about existing items, it helps generate unique results.

Use Case: When generating new test cases, provide existing tests as context to avoid duplicates.

Copy code
// Provide existing tests as context and enable the flag
const existingTests = getLinkedTests(reqId)
await TDConnection.Aviator()
  .prompt()
  .instructions('Generate additional test cases')
  .context({ 
    requirement: req,
    existingTests: existingTests  // Provide existing items
  })
  .avoidDuplication()             // Signal to AI to avoid duplicates
  .format(TDConnection.Formats.TestCases)
  .send()

.attachment(attachmentObj: any): this

Add a media attachment (image, video, audio) for the AI to analyze.

Copy code
// Get attachment from requirement
const req = TDConnection.ReqFactory.Item(reqId)
const attachments = req.Attachments.NewList('')
const firstAttachment = attachments[0]

  // Add attachment to prompt
  .attachment(firstAttachment)

Supported Formats:

Type Extensions
Images png, jpg, jpeg, webp, heic, heif, gif, bmp
Video mp4, mov, avi, webm, mkv, mpeg, wmv, 3gp, flv
Audio wav, mp3, aac, ogg, flac, aiff, m4a

Example - Generate Tests from Video:

Copy code
const response = await TDConnection.Aviator()
  .prompt()
  .persona('You are a QA expert analyzing video recordings')
  .instructions('Analyze the video and generate test cases')
  .attachment(videoAttachment)
  .format(TDConnection.Formats.TestCases)
  .send({ loadingTitle: 'Analyzing video...' })

// Handle size/timeout errors
if (response.statusCode === 408) {
  MsgBox('Request timed out. Try a shorter video.')
  return
}
if (response.statusCode === 413) {
  MsgBox('File too large. Maximum size is 10MB.')
  return
}

Notes:

  • Maximum attachment size: 10MB
  • The AI will analyze the media content along with any text context provided
  • For defects, you can extract reproduction steps from video recordings

.send(options?: SendOptions): Promise<AviatorResponse>

Execute the prompt and return a response.

Copy code
const response = await prompt.send()

// With loading modal
const response = await prompt.send({
  showLoading: true,
  loadingTitle: 'Generating Test Cases...'
})

// Silent mode (no UI)
const response = await prompt.send({ showLoading: false })

SendOptions:

Option Type Default Description
showLoading boolean true Show loading modal
loadingTitle string 'Processing...' Loading modal title

Prompt Construction Example

Understanding how the API constructs the final prompt:

Your Code:

Copy code
await TDConnection.Aviator()
  .prompt()
  .persona('You are a senior QA engineer')
  .instructions('Generate test cases')
  .instructions('Include edge cases')
  .context({
    feature: 'Login',
    priority: 'High'
  })
  .format(TDConnection.Formats.TestCases)
  .maxResults(3)
  .send()

Resulting Prompt Sent to AI:

Copy code
PERSONA:
You are a senior QA engineer

INSTRUCTIONS:
Generate test cases
Include edge cases

CONTEXT:
{
  "feature": "Login",
  "priority": "High"
}

OUTPUT FORMAT:
[
  {
    "name": "string",
    "description": "string",
    "steps": [...]
  }
]

CONSTRAINTS:
- Generate exactly 3 items
- Return valid JSON only

How Multiple .instructions() Work:

Instructions are concatenated with newlines:

Copy code
.instructions('First instruction')
.instructions('Second instruction')

Becomes:

Copy code
First instruction
Second instruction

Best Practice: Use multiple .instructions() for clarity:

Good instructions:

Copy code
.instructions('Generate 5 test cases')
.instructions('Include both happy path and error scenarios')
.instructions('Add detailed step-by-step instructions')

Less clear intructions:

Copy code
.instructions('Generate 5 test cases including both happy path and error scenarios with detailed step-by-step instructions')

AviatorResponse API

Overview

AviatorResponse wraps the AI response with auto-parsing and helper methods.

Properties

.data: any

Auto-parsed and normalized response data.

Copy code
const response = await TDConnection.Aviator().prompt().send()

console.log(response.data)
// → [{ name: "Test 1", description: "..." }, ...]

.raw: string

Original AI response (for debugging).

Copy code
console.log(response.raw)
// → "```json\n[{\"title\":\"Test 1\"}]\n```"

Methods

.isEmpty(): boolean

Check if the response contains valid data.

Copy code
if (response.isEmpty()) {
  MsgBox('No results generated.')
  return
}

.isList(): boolean

Check if the response is an array.

Copy code
if (response.isList()) {
  console.log(`Generated ${response.asList().length} items`)
}

.asList(): array

Get response as an array (converts if needed).

Copy code
const items = response.asList()
items.forEach((item) => console.log(item.name))

.first(): object | null

Get the first item from the response.

Copy code
const firstItem = response.first()
if (firstItem) {
  console.log(`First item: ${firstItem.name}`)
}

.mapToSuggestions(mapping: SuggestionFieldMapping): this

Map custom format fields to modal-expected names.

Copy code
// Your custom format uses 'scenarioTitle' and 'given'
const selected = await response
  .mapToSuggestions({
    name: 'scenarioTitle', // Map scenarioTitle → name
    description: 'given' // Map given → description
  })
  .showSuggestions({ title: 'BDD Scenarios' })

.showSuggestions(options?: SuggestionsOptions): Promise<array | null>

Display a modal for user to review and select items.

See ShowSuggestions Modal API for details.

ShowSuggestions Modal API

Overview

The ShowSuggestions modal provides a standardized UI for presenting AI-generated suggestions to users for review and selection.

Two Usage Patterns

Copy code
const response = await TDConnection.Aviator()
  .prompt()
  .instructions('Generate test cases')
  .format(TDConnection.Formats.TestCases)
  .send()

const selected = await response.showSuggestions({
  title: 'Generated Test Cases',
  description: 'Select test cases to create'
})

2. Standalone

Use when you have pre-existing data to display.

Copy code
const selected = await TDConnection.Aviator().showSuggestionsModal(
  [
    { name: 'Test 1', description: 'Login with valid credentials' },
    { name: 'Test 2', description: 'Login with invalid password' }
  ],
  {
    title: 'Import Test Cases',
    description: 'Select tests to import',
    multiSelect: true
  }
)
Option Type Default Description
title string 'AI Suggestions' Modal header title
description string 'Select items' Subtitle/instructions
multiSelect boolean true Allow multiple selections (checkboxes) vs single (radio)
buttonLabel string Auto Custom confirm button text
allowCustomInput boolean false Allow users to add custom items
type number Auto Modal type hint

Return Values

User confirms selection:

Copy code
// multiSelect: true
;[
  { name: 'Item 1', description: '...', ...otherFields },
  { name: 'Item 2', description: '...', ...otherFields }
][
  // multiSelect: false
  { name: 'Selected Item', description: '...', ...otherFields }
]

User cancels:

Copy code
null // or undefined

Complete Example

Copy code
const response = await TDConnection.Aviator()
  .prompt()
  .persona('Product Manager')
  .instructions('Generate user stories for the shopping cart feature')
  .format(TDConnection.Formats.UserStories)
  .maxResults(3)
  .send({ loadingTitle: 'Generating user stories...' })

const selected = await response.showSuggestions({
  title: 'AI-Generated User Stories',
  description: 'Review and select stories to add to the backlog',
  multiSelect: true,
  buttonLabel: 'Add to Backlog',
  allowCustomInput: true
})

if (selected?.length > 0) {
  selected.forEach((story) => {
    createUserStory(story.name, story.description)
  })
  MsgBox(`Created ${selected.length} user stories.`)
}

Using show suggestions

Use ShowSuggestions when:

  • User needs to review AI output before action
  • Multiple items generated, user should select
  • User might want to edit/customize suggestions
  • Operation creates/modifies entities

Do not use ShowSuggestions when:

  • Silent background operations (use .send({ showLoading: false }))
  • Automated batch processes
  • Response is simple yes/no or true/false
  • User doesn't need to approve the output

Handling Cancellation

Copy code
const selected = await response.showSuggestions({ title: 'Items' })

// Always check for cancellation
if (!selected || selected.length === 0) {
  MsgBox('No items selected. Operation cancelled.')
  return
}

// Safe to proceed
processSelectedItems(selected)

Auto-Parsing Pipeline

Overview

The Aviator API automatically processes AI responses to ensure consistent, usable data structures. This pipeline extracts JSON from markdown, normalizes field names, and validates structure.

Pipeline Stages

Copy code
Raw AI Response
    ↓
1. Markdown Code Block Detection
    ↓
2. JSON Extraction
    ↓
3. Field Name Normalization
    ↓
4. Structure Validation
    ↓
response.data (Clean, normalized data)

Stage 1: Markdown Code Block Detection

AI models often wrap JSON in markdown. The parser auto-extracts it:

Raw AI Response:

Copy code
Here are the test cases:

```json
[{ "title": "Test 1", "reasoning": "Validates login" }]
```

Hope this helps!

Extracted JSON:

Copy code
[{ "title": "Test 1", "reasoning": "Validates login" }]

Supported Formats:

  • ```json ... ```
  • ```javascript ... ```
  • ``` ... ``` (no language)

Stage 2: Field Name Normalization

Different AI models use different field names. The parser normalizes them:

Raw AI Response:

Copy code
[
  { "title": "Login Test", "reasoning": "Verify authentication" },
  { "name": "Logout Test", "description": "Verify logout" }
]

Normalized response.data:

Copy code
[
  { "name": "Login Test", "description": "Verify authentication" },
  { "name": "Logout Test", "description": "Verify logout" }
]

Stage 3: Handling Unexpected Formats

Scenario: Plain Text Response

AI Returns:

Copy code
Test 1: Verify login
Test 2: Verify logout

Normalized:

Copy code
{
  "content": "Test 1: Verify login\nTest 2: Verify logout"
}

Scenario: Mixed Content

AI Returns:

Copy code
I've generated these:

```json
[{"name": "Test 1"}]

Let me know!

Copy code

**Normalized:**
```json
[
  {"name": "Test 1"}
]

Accessing Raw vs Parsed

Copy code
const response = await TDConnection.Aviator().prompt().send()

// Parsed and normalized (recommended)
console.log(response.data)
// → [{ name: "Test 1", description: "..." }]

// Original raw response (for debugging)
console.log(response.raw)
// → "```json\n[{\"title\":\"Test 1\"}]\n```"

Error Handling

If parsing fails completely:

Copy code
// For list formats
response.data = []
response.isEmpty() // → true

// For object formats
response.data = null
response.isEmpty() // → true

Always check before processing:

Copy code
if (response.isEmpty()) {
  MsgBox('AI could not generate valid results. Please try again.')
  return
}

Response Normalization Rules

Overview

The API applies consistent field name mapping to ensure compatibility between different AI outputs and application expectations.

Field Mapping Table

AI Response Field Maps To Priority Use Case
title name 1 (highest) Primary identifier
reasoning description 1 Explanation/rationale
rationale description 2 Alternative explanation
reason description 3 Short explanation
summary description 4 Summary text
details description 5 Detailed info
content description 6 (fallback) Generic content

Priority Rules

When multiple mappable fields exist, highest priority wins:

AI Returns:

Copy code
{
  "title": "Test Case 1",
  "name": "Other Name",
  "reasoning": "Primary reason",
  "summary": "Summary text"
}

Normalized To:

Copy code
{
  "name": "Test Case 1", // title → name (priority 1)
  "description": "Primary reason" // reasoning → description (priority 1)
}

Field Preservation

Fields not in the mapping table are preserved as-is:

AI Returns:

Copy code
{
  "title": "Login Test",
  "reasoning": "Verify auth",
  "priority": "High",
  "customField": "Custom Value"
}

Normalized:

Copy code
{
  "name": "Login Test",
  "description": "Verify auth",
  "priority": "High", // Preserved
  "customField": "Custom Value" // Preserved
}

Array Normalization

Normalization applies per item independently:

AI Returns:

Copy code
[
  { "title": "Item 1", "reasoning": "Reason 1" },
  { "name": "Item 2", "description": "Reason 2" },
  { "title": "Item 3", "summary": "Reason 3" }
]

Normalized:

Copy code
[
  { "name": "Item 1", "description": "Reason 1" },
  { "name": "Item 2", "description": "Reason 2" },
  { "name": "Item 3", "description": "Reason 3" }
]

Nested Objects

Normalization is shallow (top-level only):

AI Returns:

Copy code
{
  "title": "Test Case",
  "steps": [{ "title": "Step 1", "details": "Click login" }]
}

Normalized:

Copy code
{
  "name": "Test Case",
  "steps": [
    { "title": "Step 1", "details": "Click login" } // NOT normalized
  ]
}

For nested normalization, apply manually:

Copy code
response.data = response.data.map((item) => ({
  ...item,
  steps: item.steps.map((step) => ({
    name: step.title || step.name,
    description: step.details || step.description
  }))
}))

Debugging Normalization

Copy code
const response = await TDConnection.Aviator().prompt().send()

console.log('Raw:', response.raw)
console.log('Normalized:', response.data)

const wasNormalized = JSON.stringify(response.raw) !== JSON.stringify(response.data)
console.log('Normalization applied:', wasNormalized)

OutputFormatBuilder

Overview

Create custom output schemas for specialized AI responses.

Methods

.addField(name, type, description): this

Add a field to the schema.

Copy code
.addField('name', 'string', 'Test case name')
.addField('priority', 'number', 'Priority level 1-5')
.addField('tags', 'array', 'List of tags')

Supported Types:

  • string, number, boolean, array, object

.addNestedField(parent, child, type, description): this

Add a nested field.

Copy code
.addNestedField('metadata', 'author', 'string', 'Author name')
.addNestedField('metadata', 'date', 'string', 'Creation date')

.asList(): this

Set output as an array.

Copy code
.asList()  // Returns: [{ field1: ..., field2: ... }, ...]

.asObject(): this

Set output as a single object (default).

Copy code
.asObject()  // Returns: { field1: ..., field2: ... }

.build(): OutputFormat

Build and return the format schema.

Copy code
const format = builder.build()

Complete Example

Copy code
const bddFormat = TDConnection.Aviator()
  .buildFormat()
  .addField('scenarioName', 'string', 'Scenario name')
  .addField('given', 'string', 'Given condition')
  .addField('when', 'string', 'When action')
  .addField('then', 'string', 'Then expectation')
  .asList()
  .build()

const response = await TDConnection.Aviator()
  .prompt()
  .instructions('Generate BDD scenarios')
  .format(bddFormat)
  .send()

// Map custom fields to modal format
const selected = await response
  .mapToSuggestions({
    name: 'scenarioName',
    description: 'given'
  })
  .showSuggestions({ title: 'BDD Scenarios' })

Predefined Formats

TDConnection.Formats.TestCases

Generates test case objects.

Output Structure:

Copy code
[
  {
    "name": "string",
    "description": "string",
    "test_type": "string",
    "priority": "string",
    "steps": [
      {
        "stepNumber": "number",
        "description": "string",
        "expected_result": "string"
      }
    ]
  }
]

TDConnection.Formats.UserStories

Generates user story objects.

Output Structure:

Copy code
[
  {
    "name": "string",
    "description": "string",
    "acceptanceCriteria": ["string"],
    "priority": "string"
  }
]

TDConnection.Formats.ComplianceCheck

Validates compliance.

Output Structure:

Copy code
{
  "compliant": "boolean",
  "reason": "string",
  "recommendations": ["string"]
}

TDConnection.Formats.Defect

Analyzes defects.

Output Structure:

Copy code
{
  "name": "string",
  "description": "string",
  "severity": "string",
  "rootCause": "string",
  "steps": ["string"]
}

TDConnection.Formats.Text

Plain text response.

Output: String or { content: "string" }

TDConnection.Formats.List

Simple list of strings.

Output:["string", "string", ...]

TDConnection.Formats.JSON

Raw JSON response (no parsing).

Output: AI response as-is

Utility Functions

TDConnection.Utils.stripHtml(html: string): string

Remove HTML tags from text.

Copy code
const clean = TDConnection.Utils.stripHtml('<p>Hello <b>World</b></p>')
// → "Hello World"

TDConnection.Utils.normalizeWhitespace(text: string): string

Collapse multiple spaces/newlines.

Copy code
const clean = TDConnection.Utils.normalizeWhitespace('Hello    World\n\n\nTest')
// → "Hello World Test"

TDConnection.Utils.truncate(text: string, maxLength: number): string

Truncate text to max length.

Copy code
const short = TDConnection.Utils.truncate('Long text here', 10)
// → "Long text..."