This library provides a Dart client for interacting with Genkit flows, enabling type-safe communication for both unary and streaming operations.
Import the library and define your remote actions.
import 'package:genkit/genkit.dart';
Remote actions represent a remote Genkit action (like flows, models and prompts) that can be invoked or streamed.
// Create a remote action for a flow that takes a String and returns a String
final stringAction = defineRemoteAction(
url: 'http://localhost:3400/my-flow',
fromResponse: (data) => data as String,
);
// Create a remote action for custom objects
final customAction = defineRemoteAction(
url: 'http://localhost:3400/custom-flow',
fromResponse: (data) => MyOutput.fromJson(data),
);
The code assumes that you have my-flow
and custom-flow
deployed at those URLs. See https://genkit.dev/docs/deploy-node/ or https://genkit.dev/go/docs/deploy/ for details.
final action = defineRemoteAction(
url: 'http://localhost:3400/echo-string',
fromResponse: (data) => data as String,
);
try {
final response = await action(input: 'Hello from Dart!');
print('Flow Response: $response');
} catch (e) {
print('Error calling flow: $e');
}
class MyInput {
final String message;
final int count;
MyInput({required this.message, required this.count});
Map<String, dynamic> toJson() => {
'message': message,
'count': count,
};
}
class MyOutput {
final String reply;
final int newCount;
MyOutput({required this.reply, required this.newCount});
factory MyOutput.fromJson(Map<String, dynamic> json) => MyOutput(
reply: json['reply'] as String,
newCount: json['newCount'] as int,
);
}
final action = defineRemoteAction(
url: 'http://localhost:3400/process-object',
fromResponse: (data) => MyOutput.fromJson(data),
);
final input = MyInput(message: 'Process this data', count: 10);
try {
final output = await action(input: input);
print('Flow Response: ${output.reply}, ${output.newCount}');
} catch (e) {
print('Error calling flow: $e');
}
Use the stream
method for flows that stream multiple chunks of data and then return a final response. It returns a FlowStreamResponse
containing both the stream
and the response
future.
final streamAction = defineRemoteAction(
url: 'http://localhost:3400/stream-story',
fromResponse: (data) => data as String,
fromStreamChunk: (data) => data['chunk'] as String,
);
try {
final streamResponse = streamAction.stream(
input: 'Tell me a short story about a Dart developer.',
);
print('Streaming chunks:');
await for (final chunk in streamResponse.stream) {
print('Chunk: $chunk');
}
final finalResult = await streamResponse.response;
print('\nFinal Response: $finalResult');
} catch (e) {
print('Error calling streamFlow: $e');
}
class StreamChunk {
final String content;
StreamChunk({required this.content});
factory StreamChunk.fromJson(Map<String, dynamic> json) => StreamChunk(
content: json['content'] as String,
);
}
final streamAction = defineRemoteAction(
url: 'http://localhost:3400/stream-process',
fromResponse: (data) => MyOutput.fromJson(data),
fromStreamChunk: (data) => StreamChunk.fromJson(data),
);
final input = MyInput(message: 'Stream this data', count: 5);
try {
final streamResponse = streamAction.stream(input: input);
print('Streaming chunks:');
await for (final chunk in streamResponse.stream) {
print('Chunk: ${chunk.content}');
}
final finalResult = await streamResponse.response;
print('\nFinal Response: ${finalResult.reply}');
} catch (e) {
print('Error calling streaming flow: $e');
}
You can provide custom headers for individual requests:
final response = await action(
input: 'test input',
headers: {'Authorization': 'Bearer your-token'},
);
// For streaming
final streamResponse = action.stream(
input: 'test input',
headers: {'Authorization': 'Bearer your-token'},
);
You can also set default headers when creating the remote action:
final action = defineRemoteAction(
url: 'http://localhost:3400/my-flow',
fromResponse: (data) => data as String,
defaultHeaders: {'Authorization': 'Bearer your-token'},
);
The library throws GenkitException
for various error conditions:
try {
final result = await action(input: 'test');
} on GenkitException catch (e) {
print('Genkit error: ${e.message}');
print('Status code: ${e.statusCode}');
print('Details: ${e.details}');
} catch (e) {
print('Other error: $e');
}
O
: The type of the output data from the flow's final responseS
: The type of the data chunks streamed from the flow (usevoid
for non-streaming flows)
fromResponse
: Converts the JSON response data to your output typeO
fromStreamChunk
: (Optional) Converts JSON chunk data to your stream chunk typeS
Make sure your custom classes have appropriate toJson()
and fromJson()
methods for serialization and deserialization.