Every terminal result separates the answer intended for a person from status and structured application data. In Kestrel 0.7, the readable answer is always available as assistantText: string | null.
type RunnerTerminalResult = {
output: NormalizedOutput;
assistantText: string | null;
finalizedPayload?: unknown;
operatorAffordance?: unknown;
};Read each field
| Field | Meaning |
|---|---|
output | Runtime status, run identity, final step, checkpoint, quality, and wait state |
assistantText | Non-empty human-facing assistant text, or null when no assistant message exists |
finalizedPayload | Optional structured data; it does not own display text |
operatorAffordance | Optional control state for a waiting or completed run |
Add an assistant message to the interface only when assistantText is non-null. Handle finalizedPayload separately so invalid structured data cannot erase or replace a valid answer.
Keep four concerns separate
assistantTextis what a person may read as the assistant response.outputdescribes runtime status and normalized execution data.finalizedPayloadcarries optional application-specific structured data.- The terminal event type distinguishes completed, failed, and cancelled outcomes; waiting information explains how paused work may continue.
const result = terminal.payload.result;
if (result.assistantText !== null) {
appendAssistantMessage(result.assistantText);
}
persistRunOutcome({
type: terminal.type,
output: result.output,
finalizedPayload: result.finalizedPayload,
});