# Power Automate expressions — EP026

Version 1.0 · 1 November 2026. These three expressions were saved in the tested flow. Action names must match your flow. Paste without code fences. The reply condition is compared to boolean true in the Condition action.

## classifierOutput

Read the structured output from the first AI prompt. The question-mark operators allow missing properties to return null; they do not validate the schema.

```text
body('Run_a_prompt')?['responsev2']?['predictionOutput']?['structuredOutput']
```

## answerOutput

Convert the second prompt’s JSON text to an object before reading answerFound, kbIds, answerText and evidenceQuotes. Invalid JSON fails this expression.

```text
json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])
```

## replyCondition

Require supported classification, one candidate article, complete bounded inputs, nonempty answer, quotes found in KBContext, and one matching KB ID. This gate is not proof that every generated sentence is supported.

```text
and(equals(json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])?['answerFound'],true),equals(body('Run_a_prompt')?['responsev2']?['predictionOutput']?['structuredOutput']?['requiresHuman'],false),contains(createArray('AccountAccess','EmailOutlook','TeamsMeetings','FilesSharePointOneDrive','DevicesNetwork','SoftwareRequests'),body('Run_a_prompt')?['responsev2']?['predictionOutput']?['structuredOutput']?['category']),equals(length(body('Filter_array')),1),lessOrEquals(length(body('Html_to_text')),8000),lessOrEquals(length(variables('KBContext')),20000),not(empty(json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])?['answerText'])),greater(length(json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])?['evidenceQuotes']),0),empty(body('Filter_array_1')),equals(length(json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])?['kbIds']),1),startsWith(variables('KBContext'),concat('File: ',first(json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])?['kbIds']),'-',body('Run_a_prompt')?['responsev2']?['predictionOutput']?['structuredOutput']?['category'],'.txt')))
```

## Input bounds and article content

The following are individual expressions used by the build. Insert them in the relevant input or text template, not as an entire flow definition.

```text
take(body('Html_to_text'),8000)
```

This limits text sent to AI. The delivery gate separately checks the original length.

```text
File: @{items('Apply_to_each')?['{FilenameWithExtension}']}
@{body('Get_file_content')}
```

Append this text inside the sequential article loop. The TXT connector response in this demo was plain text; do not automatically add base64 decoding.

## Rebuild notes

The exact six-file allowlist, review cutoff, invalid-quote filter, HTML escaping and status expressions must also be wired according to BUILD-GUIDE.md and verified in your environment. This file is not a complete importable flow export. The fixed review cutoff is 2026-12-01 UTC; review the articles and update the gate before later use.

## Additional expressions copied from the actual flow

The following were read from Code view on 1 November 2026. A leading @ denotes workflow-definition syntax; remove that leading @ when entering the expression in the expression editor. Keep @{...} in mixed text templates. No connection or tenant identifiers are included.

### filter-array / from

```text
@outputs('Get_files_(properties_only)')?['body/value']
```

### filter-array / where

```text
@and(equals(item()?['{IsFolder}'],false),contains(createArray('KB-001-AccountAccess.txt','KB-002-EmailOutlook.txt','KB-003-TeamsMeetings.txt','KB-004-FilesSharePointOneDrive.txt','KB-005-DevicesNetwork.txt','KB-006-SoftwareRequests.txt'),item()?['{FilenameWithExtension}']),endsWith(item()?['{FilenameWithExtension}'],concat('-',body('Run_a_prompt')?['responsev2']?['predictionOutput']?['structuredOutput']?['category'],'.txt')),lessOrEquals(formatDateTime(utcNow(),'yyyy-MM-dd'),'2026-12-01'))
```

### invalid-quotes / from

```text
@coalesce(json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])?['evidenceQuotes'],json('[]'))
```

### invalid-quotes / where

```text
@or(empty(item()),not(contains(variables('KBContext'),item())))
```

### update-status / item/MessageKey

```text
@triggerOutputs()?['body/internetMessageId']
```

### update-status / item/Status/Value

```text
@if(equals(actions('Reply_to_email_(V3)')?['status'],'Succeeded'),'Sent',if(equals(actions('Post_message_in_a_chat_or_channel')?['status'],'Succeeded'),'AwaitingTunde',if(contains(createArray('Failed','TimedOut'),actions('Reply_to_email_(V3)')?['status']),'SendUnknown','Failed')))
```

### update-status / item/CompletedUtc

```text
@utcNow()
```

### classifier-input / EmailText

```text
Subject: @{triggerOutputs()?['body/subject']}
Body: @{take(body('Html_to_text'),8000)}
```

### answer-input / KBContext

```text
@if(empty(variables('KBContext')),'No matching approved KB found.',take(variables('KBContext'),20000))
```

### answer-input / EmailText

```text
Subject: @{triggerOutputs()?['body/subject']}
Body: @{take(body('Html_to_text'),8000)}
```

### reply / escaped answer

```text
replace(replace(replace(json(body('Run_a_prompt_1')?['responsev2']?['predictionOutput']?['text'])?['answerText'],'&','&amp;'),'<','&lt;'),'>','&gt;')
```

