blob: edc83ee27174fbc7f3d1ec20e645e6f25bc90727 [file] [log] [blame]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of 'api.dart';
/// The parameters for an `elicitation/create` request.
extension type ElicitRequest._fromMap(Map<String, Object?> _value)
implements Request {
static const methodName = 'elicitation/create';
factory ElicitRequest({
required String message,
required Schema requestedSchema,
}) {
assert(
validateRequestedSchema(requestedSchema),
'Invalid requestedSchema. Must be a flat object of primitive values.',
);
return ElicitRequest._fromMap({
'message': message,
'requestedSchema': requestedSchema,
});
}
/// A message to display to the user when collecting the response.
String get message {
final message = _value['message'] as String?;
if (message == null) {
throw ArgumentError('Missing required message field in $ElicitRequest');
}
return message;
}
/// A JSON schema that describes the expected response.
///
/// The content may only consist of a flat object (no nested maps or lists)
/// with primitive values (`String`, `num`, `bool`, `enum`).
///
/// You can use [validateRequestedSchema] to validate that a schema conforms
/// to these limitations.
Schema get requestedSchema {
final requestedSchema = _value['requestedSchema'] as Schema?;
if (requestedSchema == null) {
throw ArgumentError(
'Missing required requestedSchema field in $ElicitRequest',
);
}
return requestedSchema;
}
/// Validates the [schema] to make sure that it conforms to the
/// limitations of the spec.
///
/// See also: [requestedSchema] for a description of the spec limitations.
static bool validateRequestedSchema(Schema schema) {
if (schema.type != JsonType.object) {
return false;
}
final objectSchema = schema as ObjectSchema;
final properties = objectSchema.properties;
if (properties == null) {
return true; // No properties to validate.
}
for (final propertySchema in properties.values) {
// Combinators would mean it's not a simple primitive type.
if (propertySchema.allOf != null ||
propertySchema.anyOf != null ||
propertySchema.oneOf != null ||
propertySchema.not != null) {
return false;
}
switch (propertySchema.type) {
case JsonType.string:
case JsonType.num:
case JsonType.int:
case JsonType.bool:
case JsonType.enumeration:
break;
case JsonType.object:
case JsonType.list:
case JsonType.nil:
case null:
// Disallowed, or no type specified.
return false;
}
}
return true;
}
}
/// The client's response to an `elicitation/create` request.
extension type ElicitResult.fromMap(Map<String, Object?> _value)
implements Result {
factory ElicitResult({
required ElicitationAction action,
Map<String, Object?>? content,
}) => ElicitResult.fromMap({'action': action.name, 'content': content});
/// The action taken by the user in response to an elicitation request.
///
/// - [ElicitationAction.accept]: The user accepted the request and provided
/// the requested information.
/// - [ElicitationAction.reject]: The user explicitly declined the action.
/// - [ElicitationAction.cancel]: The user dismissed without making an
/// explicit choice.
ElicitationAction get action {
final action = _value['action'] as String?;
if (action == null) {
throw ArgumentError('Missing required action field in $ElicitResult');
}
return ElicitationAction.values.byName(action);
}
/// The content of the response, if the user accepted the request.
///
/// Must be `null` if the user didn't accept the request.
///
/// The content must conform to the [ElicitRequest]'s `requestedSchema`.
Map<String, Object?>? get content =>
_value['content'] as Map<String, Object?>?;
}
/// The action taken by the user in response to an elicitation request.
enum ElicitationAction {
/// The user accepted the request and provided the requested information.
accept,
/// The user explicitly declined the action.
reject,
/// The user dismissed without making an explicit choice.
cancel,
}