feat: HubClient.listFlows + runSavedFlow

Two more wrappers for Studio's new Flows page. Saved flows can
be listed (FlowSummary: name + path + size) and executed by
name with a map of named text inputs. Returns a SubmitResponse
whose `outputs` map carries the flow's declared outputs as
Payloads.

Common payload type re-exposed via the `Payload` typedef from
common.pb.dart so the Studio side can pattern-match on
text/json/bytes/file without dragging in proto imports.

Bumps fai_dart_sdk 0.4.0 -> 0.5.0.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-05-05 23:35:47 +02:00
parent 4b67055fc7
commit 9249fbe4f5

View file

@ -6,6 +6,7 @@
import 'package:grpc/grpc.dart'; import 'package:grpc/grpc.dart';
import 'generated/fai/v1/common.pb.dart' as pb_common;
import 'generated/fai/v1/hub.pb.dart' as pb; import 'generated/fai/v1/hub.pb.dart' as pb;
import 'generated/fai/v1/hub.pbgrpc.dart' as grpc_hub; import 'generated/fai/v1/hub.pbgrpc.dart' as grpc_hub;
import 'generated/google/protobuf/empty.pb.dart' show Empty; import 'generated/google/protobuf/empty.pb.dart' show Empty;
@ -41,6 +42,9 @@ typedef PendingApprovalEntry = pb.PendingApprovalEntry;
typedef DeclaredService = pb.DeclaredService; typedef DeclaredService = pb.DeclaredService;
typedef VerifyEventChainResponse = pb.VerifyEventChainResponse; typedef VerifyEventChainResponse = pb.VerifyEventChainResponse;
typedef ModuleInfoResponse = pb.ModuleInfoResponse; typedef ModuleInfoResponse = pb.ModuleInfoResponse;
typedef FlowSummary = pb.FlowSummary;
typedef Payload = pb_common.Payload;
typedef SubmitResponse = pb.SubmitResponse;
/// Typed client for the FI Hub gRPC surface. Construct once, /// Typed client for the FI Hub gRPC surface. Construct once,
/// reuse for the process lifetime, call [close] on shutdown. /// reuse for the process lifetime, call [close] on shutdown.
@ -159,6 +163,29 @@ class HubClient {
return r.services; return r.services;
} }
/// All saved flows known to the hub. Each entry carries the
/// flow name, on-disk path and byte size.
Future<List<FlowSummary>> listFlows() async {
final r = await _admin.listFlows(Empty());
return r.flows;
}
/// Run a saved flow by name with the supplied named inputs.
/// Each input value is wrapped as a text Payload the most
/// common case for human-driven runs from Studio. Callers
/// that need bytes / file payloads use the lower-level
/// SubmitRequest path.
Future<SubmitResponse> runSavedFlow({
required String name,
required Map<String, String> textInputs,
}) async {
final req = pb.RunSavedFlowRequest()..name = name;
for (final entry in textInputs.entries) {
req.inputs[entry.key] = pb_common.Payload()..text = entry.value;
}
return _admin.runSavedFlow(req);
}
/// Closes the gRPC channel. Idempotent. /// Closes the gRPC channel. Idempotent.
Future<void> close() async { Future<void> close() async {
await _channel.shutdown(); await _channel.shutdown();