From 9249fbe4f565c8c65c3d7408609728690f3638bd Mon Sep 17 00:00:00 2001 From: flemming-it Date: Tue, 5 May 2026 23:35:47 +0200 Subject: [PATCH] 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 --- lib/src/hub_client.dart | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/src/hub_client.dart b/lib/src/hub_client.dart index b8173c5..2c3a795 100644 --- a/lib/src/hub_client.dart +++ b/lib/src/hub_client.dart @@ -6,6 +6,7 @@ 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.pbgrpc.dart' as grpc_hub; import 'generated/google/protobuf/empty.pb.dart' show Empty; @@ -41,6 +42,9 @@ typedef PendingApprovalEntry = pb.PendingApprovalEntry; typedef DeclaredService = pb.DeclaredService; typedef VerifyEventChainResponse = pb.VerifyEventChainResponse; typedef ModuleInfoResponse = pb.ModuleInfoResponse; +typedef FlowSummary = pb.FlowSummary; +typedef Payload = pb_common.Payload; +typedef SubmitResponse = pb.SubmitResponse; /// Typed client for the F∆I Hub gRPC surface. Construct once, /// reuse for the process lifetime, call [close] on shutdown. @@ -159,6 +163,29 @@ class HubClient { return r.services; } + /// All saved flows known to the hub. Each entry carries the + /// flow name, on-disk path and byte size. + Future> 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 runSavedFlow({ + required String name, + required Map 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. Future close() async { await _channel.shutdown();