feat: updateSystemAi + testSystemAi RPCs (v0.5.0)
`HubClient.updateSystemAi(...)` persists a new System-AI config to ~/.fai/config.yaml AND hot-reloads the live hub state in one round-trip; returns the resulting SystemAiStatus so the UI refreshes without a second call. `HubClient.testSystemAi()` probes the configured provider with a tiny ping and returns the same error-kind taxonomy as askAi. Studio's "Test connection" button uses this. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
f0db42264f
commit
8798119903
5 changed files with 203 additions and 1 deletions
|
|
@ -3037,6 +3037,114 @@ class AskAiResponse extends $pb.GeneratedMessage {
|
||||||
void clearLatencyMs() => $_clearField(3);
|
void clearLatencyMs() => $_clearField(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UpdateSystemAiRequest extends $pb.GeneratedMessage {
|
||||||
|
factory UpdateSystemAiRequest({
|
||||||
|
$core.String? provider,
|
||||||
|
$core.String? endpoint,
|
||||||
|
$core.String? model,
|
||||||
|
$core.String? apiKeyEnv,
|
||||||
|
$core.String? privacyMode,
|
||||||
|
}) {
|
||||||
|
final $result = create();
|
||||||
|
if (provider != null) {
|
||||||
|
$result.provider = provider;
|
||||||
|
}
|
||||||
|
if (endpoint != null) {
|
||||||
|
$result.endpoint = endpoint;
|
||||||
|
}
|
||||||
|
if (model != null) {
|
||||||
|
$result.model = model;
|
||||||
|
}
|
||||||
|
if (apiKeyEnv != null) {
|
||||||
|
$result.apiKeyEnv = apiKeyEnv;
|
||||||
|
}
|
||||||
|
if (privacyMode != null) {
|
||||||
|
$result.privacyMode = privacyMode;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
UpdateSystemAiRequest._() : super();
|
||||||
|
factory UpdateSystemAiRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||||
|
factory UpdateSystemAiRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||||
|
|
||||||
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateSystemAiRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'fai.v1'), createEmptyInstance: create)
|
||||||
|
..aOS(1, _omitFieldNames ? '' : 'provider')
|
||||||
|
..aOS(2, _omitFieldNames ? '' : 'endpoint')
|
||||||
|
..aOS(3, _omitFieldNames ? '' : 'model')
|
||||||
|
..aOS(4, _omitFieldNames ? '' : 'apiKeyEnv')
|
||||||
|
..aOS(5, _omitFieldNames ? '' : 'privacyMode')
|
||||||
|
..hasRequiredFields = false
|
||||||
|
;
|
||||||
|
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
UpdateSystemAiRequest clone() => UpdateSystemAiRequest()..mergeFromMessage(this);
|
||||||
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||||
|
UpdateSystemAiRequest copyWith(void Function(UpdateSystemAiRequest) updates) => super.copyWith((message) => updates(message as UpdateSystemAiRequest)) as UpdateSystemAiRequest;
|
||||||
|
|
||||||
|
$pb.BuilderInfo get info_ => _i;
|
||||||
|
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static UpdateSystemAiRequest create() => UpdateSystemAiRequest._();
|
||||||
|
UpdateSystemAiRequest createEmptyInstance() => create();
|
||||||
|
static $pb.PbList<UpdateSystemAiRequest> createRepeated() => $pb.PbList<UpdateSystemAiRequest>();
|
||||||
|
@$core.pragma('dart2js:noInline')
|
||||||
|
static UpdateSystemAiRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateSystemAiRequest>(create);
|
||||||
|
static UpdateSystemAiRequest? _defaultInstance;
|
||||||
|
|
||||||
|
/// ollama / openai / lmstudio / vllm / custom (defaults to
|
||||||
|
/// ollama if empty).
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.String get provider => $_getSZ(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
set provider($core.String v) { $_setString(0, v); }
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
$core.bool hasProvider() => $_has(0);
|
||||||
|
@$pb.TagNumber(1)
|
||||||
|
void clearProvider() => $_clearField(1);
|
||||||
|
|
||||||
|
/// Full URL up to and including /v1. Empty + privacy_mode!=off
|
||||||
|
/// → returns InvalidArgument.
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.String get endpoint => $_getSZ(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
set endpoint($core.String v) { $_setString(1, v); }
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
$core.bool hasEndpoint() => $_has(1);
|
||||||
|
@$pb.TagNumber(2)
|
||||||
|
void clearEndpoint() => $_clearField(2);
|
||||||
|
|
||||||
|
/// Model identifier the provider expects. Empty +
|
||||||
|
/// privacy_mode!=off → returns InvalidArgument.
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.String get model => $_getSZ(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
set model($core.String v) { $_setString(2, v); }
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
$core.bool hasModel() => $_has(2);
|
||||||
|
@$pb.TagNumber(3)
|
||||||
|
void clearModel() => $_clearField(3);
|
||||||
|
|
||||||
|
/// Name of the env var holding the API key. Empty = no auth.
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.String get apiKeyEnv => $_getSZ(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
set apiKeyEnv($core.String v) { $_setString(3, v); }
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
$core.bool hasApiKeyEnv() => $_has(3);
|
||||||
|
@$pb.TagNumber(4)
|
||||||
|
void clearApiKeyEnv() => $_clearField(4);
|
||||||
|
|
||||||
|
/// off / redacted / full. Empty defaults to "off".
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.String get privacyMode => $_getSZ(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
set privacyMode($core.String v) { $_setString(4, v); }
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
$core.bool hasPrivacyMode() => $_has(4);
|
||||||
|
@$pb.TagNumber(5)
|
||||||
|
void clearPrivacyMode() => $_clearField(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||||
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,14 @@ class HubAdminClient extends $grpc.Client {
|
||||||
'/fai.v1.HubAdmin/AskAi',
|
'/fai.v1.HubAdmin/AskAi',
|
||||||
($0.AskAiRequest value) => value.writeToBuffer(),
|
($0.AskAiRequest value) => value.writeToBuffer(),
|
||||||
($core.List<$core.int> value) => $0.AskAiResponse.fromBuffer(value));
|
($core.List<$core.int> value) => $0.AskAiResponse.fromBuffer(value));
|
||||||
|
static final _$updateSystemAi = $grpc.ClientMethod<$0.UpdateSystemAiRequest, $0.SystemAiStatusResponse>(
|
||||||
|
'/fai.v1.HubAdmin/UpdateSystemAi',
|
||||||
|
($0.UpdateSystemAiRequest value) => value.writeToBuffer(),
|
||||||
|
($core.List<$core.int> value) => $0.SystemAiStatusResponse.fromBuffer(value));
|
||||||
|
static final _$testSystemAi = $grpc.ClientMethod<$1.Empty, $0.AskAiResponse>(
|
||||||
|
'/fai.v1.HubAdmin/TestSystemAi',
|
||||||
|
($1.Empty value) => value.writeToBuffer(),
|
||||||
|
($core.List<$core.int> value) => $0.AskAiResponse.fromBuffer(value));
|
||||||
|
|
||||||
HubAdminClient(super.channel, {super.options, super.interceptors});
|
HubAdminClient(super.channel, {super.options, super.interceptors});
|
||||||
|
|
||||||
|
|
@ -306,6 +314,23 @@ class HubAdminClient extends $grpc.Client {
|
||||||
$grpc.ResponseFuture<$0.AskAiResponse> askAi($0.AskAiRequest request, {$grpc.CallOptions? options}) {
|
$grpc.ResponseFuture<$0.AskAiResponse> askAi($0.AskAiRequest request, {$grpc.CallOptions? options}) {
|
||||||
return $createUnaryCall(_$askAi, request, options: options);
|
return $createUnaryCall(_$askAi, request, options: options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Persist a new system-AI configuration. Updates the live
|
||||||
|
/// hub state AND writes back to ~/.fai/config.yaml so the
|
||||||
|
/// change survives daemon restart. Used by Studio's settings
|
||||||
|
/// editor. Returns the resulting status (same shape as
|
||||||
|
/// SystemAiStatus) so the UI can refresh in one round-trip.
|
||||||
|
$grpc.ResponseFuture<$0.SystemAiStatusResponse> updateSystemAi($0.UpdateSystemAiRequest request, {$grpc.CallOptions? options}) {
|
||||||
|
return $createUnaryCall(_$updateSystemAi, request, options: options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Probe the configured provider with an empty ping (model
|
||||||
|
/// listing or short message). Returns the same error_kind
|
||||||
|
/// taxonomy as AskAi so Studio's "Test connection" button
|
||||||
|
/// can render the same inline fix copy.
|
||||||
|
$grpc.ResponseFuture<$0.AskAiResponse> testSystemAi($1.Empty request, {$grpc.CallOptions? options}) {
|
||||||
|
return $createUnaryCall(_$testSystemAi, request, options: options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@$pb.GrpcServiceName('fai.v1.HubAdmin')
|
@$pb.GrpcServiceName('fai.v1.HubAdmin')
|
||||||
|
|
@ -439,6 +464,20 @@ abstract class HubAdminServiceBase extends $grpc.Service {
|
||||||
false,
|
false,
|
||||||
($core.List<$core.int> value) => $0.AskAiRequest.fromBuffer(value),
|
($core.List<$core.int> value) => $0.AskAiRequest.fromBuffer(value),
|
||||||
($0.AskAiResponse value) => value.writeToBuffer()));
|
($0.AskAiResponse value) => value.writeToBuffer()));
|
||||||
|
$addMethod($grpc.ServiceMethod<$0.UpdateSystemAiRequest, $0.SystemAiStatusResponse>(
|
||||||
|
'UpdateSystemAi',
|
||||||
|
updateSystemAi_Pre,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
($core.List<$core.int> value) => $0.UpdateSystemAiRequest.fromBuffer(value),
|
||||||
|
($0.SystemAiStatusResponse value) => value.writeToBuffer()));
|
||||||
|
$addMethod($grpc.ServiceMethod<$1.Empty, $0.AskAiResponse>(
|
||||||
|
'TestSystemAi',
|
||||||
|
testSystemAi_Pre,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
($core.List<$core.int> value) => $1.Empty.fromBuffer(value),
|
||||||
|
($0.AskAiResponse value) => value.writeToBuffer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$async.Future<$0.CapabilityList> listCapabilities_Pre($grpc.ServiceCall $call, $async.Future<$1.Empty> $request) async {
|
$async.Future<$0.CapabilityList> listCapabilities_Pre($grpc.ServiceCall $call, $async.Future<$1.Empty> $request) async {
|
||||||
|
|
@ -513,6 +552,14 @@ abstract class HubAdminServiceBase extends $grpc.Service {
|
||||||
return askAi($call, await $request);
|
return askAi($call, await $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$async.Future<$0.SystemAiStatusResponse> updateSystemAi_Pre($grpc.ServiceCall $call, $async.Future<$0.UpdateSystemAiRequest> $request) async {
|
||||||
|
return updateSystemAi($call, await $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$async.Future<$0.AskAiResponse> testSystemAi_Pre($grpc.ServiceCall $call, $async.Future<$1.Empty> $request) async {
|
||||||
|
return testSystemAi($call, await $request);
|
||||||
|
}
|
||||||
|
|
||||||
$async.Future<$0.CapabilityList> listCapabilities($grpc.ServiceCall call, $1.Empty request);
|
$async.Future<$0.CapabilityList> listCapabilities($grpc.ServiceCall call, $1.Empty request);
|
||||||
$async.Future<$0.ModuleInfoResponse> moduleInfo($grpc.ServiceCall call, $0.ModuleInfoRequest request);
|
$async.Future<$0.ModuleInfoResponse> moduleInfo($grpc.ServiceCall call, $0.ModuleInfoRequest request);
|
||||||
$async.Future<$0.CheckPermissionResponse> checkPermission($grpc.ServiceCall call, $0.CheckPermissionRequest request);
|
$async.Future<$0.CheckPermissionResponse> checkPermission($grpc.ServiceCall call, $0.CheckPermissionRequest request);
|
||||||
|
|
@ -531,4 +578,6 @@ abstract class HubAdminServiceBase extends $grpc.Service {
|
||||||
$async.Future<$0.ChannelStatusResponse> channelStatus($grpc.ServiceCall call, $1.Empty request);
|
$async.Future<$0.ChannelStatusResponse> channelStatus($grpc.ServiceCall call, $1.Empty request);
|
||||||
$async.Future<$0.SystemAiStatusResponse> systemAiStatus($grpc.ServiceCall call, $1.Empty request);
|
$async.Future<$0.SystemAiStatusResponse> systemAiStatus($grpc.ServiceCall call, $1.Empty request);
|
||||||
$async.Future<$0.AskAiResponse> askAi($grpc.ServiceCall call, $0.AskAiRequest request);
|
$async.Future<$0.AskAiResponse> askAi($grpc.ServiceCall call, $0.AskAiRequest request);
|
||||||
|
$async.Future<$0.SystemAiStatusResponse> updateSystemAi($grpc.ServiceCall call, $0.UpdateSystemAiRequest request);
|
||||||
|
$async.Future<$0.AskAiResponse> testSystemAi($grpc.ServiceCall call, $1.Empty request);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -716,3 +716,22 @@ final $typed_data.Uint8List askAiResponseDescriptor = $convert.base64Decode(
|
||||||
'Cg1Bc2tBaVJlc3BvbnNlEh0KCmVycm9yX2tpbmQYASABKAlSCWVycm9yS2luZBISCgR0ZXh0GA'
|
'Cg1Bc2tBaVJlc3BvbnNlEh0KCmVycm9yX2tpbmQYASABKAlSCWVycm9yS2luZBISCgR0ZXh0GA'
|
||||||
'IgASgJUgR0ZXh0Eh0KCmxhdGVuY3lfbXMYAyABKA1SCWxhdGVuY3lNcw==');
|
'IgASgJUgR0ZXh0Eh0KCmxhdGVuY3lfbXMYAyABKA1SCWxhdGVuY3lNcw==');
|
||||||
|
|
||||||
|
@$core.Deprecated('Use updateSystemAiRequestDescriptor instead')
|
||||||
|
const UpdateSystemAiRequest$json = {
|
||||||
|
'1': 'UpdateSystemAiRequest',
|
||||||
|
'2': [
|
||||||
|
{'1': 'provider', '3': 1, '4': 1, '5': 9, '10': 'provider'},
|
||||||
|
{'1': 'endpoint', '3': 2, '4': 1, '5': 9, '10': 'endpoint'},
|
||||||
|
{'1': 'model', '3': 3, '4': 1, '5': 9, '10': 'model'},
|
||||||
|
{'1': 'api_key_env', '3': 4, '4': 1, '5': 9, '10': 'apiKeyEnv'},
|
||||||
|
{'1': 'privacy_mode', '3': 5, '4': 1, '5': 9, '10': 'privacyMode'},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Descriptor for `UpdateSystemAiRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||||
|
final $typed_data.Uint8List updateSystemAiRequestDescriptor = $convert.base64Decode(
|
||||||
|
'ChVVcGRhdGVTeXN0ZW1BaVJlcXVlc3QSGgoIcHJvdmlkZXIYASABKAlSCHByb3ZpZGVyEhoKCG'
|
||||||
|
'VuZHBvaW50GAIgASgJUghlbmRwb2ludBIUCgVtb2RlbBgDIAEoCVIFbW9kZWwSHgoLYXBpX2tl'
|
||||||
|
'eV9lbnYYBCABKAlSCWFwaUtleUVudhIhCgxwcml2YWN5X21vZGUYBSABKAlSC3ByaXZhY3lNb2'
|
||||||
|
'Rl');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,32 @@ class HubClient {
|
||||||
return _admin.askAi(pb.AskAiRequest(prompt: prompt));
|
return _admin.askAi(pb.AskAiRequest(prompt: prompt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Persist a new System-AI configuration. Validates +
|
||||||
|
/// writes back to ~/.fai/config.yaml + hot-reloads the live
|
||||||
|
/// hub state in one call. Returns the resulting status so
|
||||||
|
/// the UI can refresh in one round-trip.
|
||||||
|
Future<SystemAiStatusResponse> updateSystemAi({
|
||||||
|
required String provider,
|
||||||
|
required String endpoint,
|
||||||
|
required String model,
|
||||||
|
required String apiKeyEnv,
|
||||||
|
required String privacyMode,
|
||||||
|
}) {
|
||||||
|
return _admin.updateSystemAi(pb.UpdateSystemAiRequest(
|
||||||
|
provider: provider,
|
||||||
|
endpoint: endpoint,
|
||||||
|
model: model,
|
||||||
|
apiKeyEnv: apiKeyEnv,
|
||||||
|
privacyMode: privacyMode,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Probe the configured provider with a tiny ping. Same
|
||||||
|
/// error-kind taxonomy as [askAi].
|
||||||
|
Future<AskAiResponse> testSystemAi() {
|
||||||
|
return _admin.testSystemAi(Empty());
|
||||||
|
}
|
||||||
|
|
||||||
/// Search the hub's bundled store index. All filters are
|
/// Search the hub's bundled store index. All filters are
|
||||||
/// optional; an empty query returns the first [limit] entries
|
/// optional; an empty query returns the first [limit] entries
|
||||||
/// the index ships with.
|
/// the index ships with.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: fai_dart_sdk
|
name: fai_dart_sdk
|
||||||
description: gRPC client SDK for the F∆I Platform hub. Used by F∆I Studio and Tier-3 domain apps.
|
description: gRPC client SDK for the F∆I Platform hub. Used by F∆I Studio and Tier-3 domain apps.
|
||||||
version: 0.4.0
|
version: 0.5.0
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
repository: https://git.flemming.ws/fai/dart-sdk
|
repository: https://git.flemming.ws/fai/dart-sdk
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue