// FlowOutput — typed representation of one entry in // `SubmitResponse.outputs`. Lets Studio render text vs. JSON vs. // bytes vs. file with the right widget instead of stringifying // everything into `` placeholders. import 'dart:convert'; import 'dart:typed_data'; import 'package:fai_client_sdk/fai_client_sdk.dart' show Payload; /// One named output of a flow run. Sealed via factory constructors /// — callers pattern-match with `switch` on the runtime type to /// pick a renderer. Variants: /// /// - [FlowOutputText] : plain text. `mimeType` may be set /// (e.g. `text/markdown`) so the /// renderer can pick a Markdown widget. /// - [FlowOutputJson] : a proto Struct, already pretty- /// printed as JSON so the UI can render /// it directly. /// - [FlowOutputBytes] : raw bytes + MIME. The renderer /// decides whether to inline a preview /// (e.g. images) and exposes a /// Save-As affordance otherwise. /// - [FlowOutputFile] : a URI the host already wrote to. The /// renderer offers an Open action. /// - [FlowOutputUnknown] : oneof was empty / unset. Never /// expected in practice but kept so /// the UI never panics on a future /// schema bump. sealed class FlowOutput { const FlowOutput(); factory FlowOutput.fromPayload(Payload p) { if (p.hasText()) { return FlowOutputText(text: p.text); } if (p.hasJson()) { // proto Struct → toProto3Json gives a Dart-side // Map/List/primitive tree. We re-encode with an indent so // the UI can show the operator-friendly form directly. final tree = p.json.toProto3Json(); const encoder = JsonEncoder.withIndent(' '); return FlowOutputJson(pretty: encoder.convert(tree)); } if (p.hasBytes()) { return FlowOutputBytes( bytes: Uint8List.fromList(p.bytes.data), mimeType: p.bytes.mimeType, ); } if (p.hasFile()) { return FlowOutputFile(uri: p.file.uri, mimeType: p.file.mimeType); } return const FlowOutputUnknown(); } } class FlowOutputText extends FlowOutput { final String text; const FlowOutputText({required this.text}); } class FlowOutputJson extends FlowOutput { /// Already indented JSON, ready for SelectableText / Markdown /// code-block rendering. final String pretty; const FlowOutputJson({required this.pretty}); } class FlowOutputBytes extends FlowOutput { final Uint8List bytes; final String mimeType; const FlowOutputBytes({required this.bytes, required this.mimeType}); } class FlowOutputFile extends FlowOutput { final String uri; final String mimeType; const FlowOutputFile({required this.uri, required this.mimeType}); } class FlowOutputUnknown extends FlowOutput { const FlowOutputUnknown(); }