diff --git a/lib/models/thought.dart b/lib/models/thought.dart index 1af77a14..e49d1958 100644 --- a/lib/models/thought.dart +++ b/lib/models/thought.dart @@ -38,6 +38,31 @@ class ThinkingChunkTypeConverter int toJson(ThinkingChunkType object) => object.value; } +enum ThinkingMessagePartType { + text(0), + functionCall(1), + functionResult(2); + + const ThinkingMessagePartType(this.value); + final int value; + + static ThinkingMessagePartType fromValue(int value) { + return values.firstWhere((e) => e.value == value, orElse: () => text); + } +} + +class ThinkingMessagePartTypeConverter + implements JsonConverter { + const ThinkingMessagePartTypeConverter(); + + @override + ThinkingMessagePartType fromJson(int json) => + ThinkingMessagePartType.fromValue(json); + + @override + int toJson(ThinkingMessagePartType object) => object.value; +} + @freezed sealed class StreamThinkingRequest with _$StreamThinkingRequest { const factory StreamThinkingRequest({ @@ -77,6 +102,43 @@ sealed class SnThinkingChunk with _$SnThinkingChunk { _$SnThinkingChunkFromJson(json); } +@freezed +sealed class SnFunctionCall with _$SnFunctionCall { + const factory SnFunctionCall({ + required String id, + required String name, + required String arguments, + }) = _SnFunctionCall; + + factory SnFunctionCall.fromJson(Map json) => + _$SnFunctionCallFromJson(json); +} + +@freezed +sealed class SnFunctionResult with _$SnFunctionResult { + const factory SnFunctionResult({ + required String callId, + required dynamic result, + required bool isError, + }) = _SnFunctionResult; + + factory SnFunctionResult.fromJson(Map json) => + _$SnFunctionResultFromJson(json); +} + +@freezed +sealed class SnThinkingMessagePart with _$SnThinkingMessagePart { + const factory SnThinkingMessagePart({ + @ThinkingMessagePartTypeConverter() required ThinkingMessagePartType type, + String? text, + SnFunctionCall? functionCall, + SnFunctionResult? functionResult, + }) = _SnThinkingMessagePart; + + factory SnThinkingMessagePart.fromJson(Map json) => + _$SnThinkingMessagePartFromJson(json); +} + @freezed sealed class SnThinkingSequence with _$SnThinkingSequence { const factory SnThinkingSequence({ @@ -98,9 +160,8 @@ sealed class SnThinkingSequence with _$SnThinkingSequence { sealed class SnThinkingThought with _$SnThinkingThought { const factory SnThinkingThought({ required String id, - String? content, + @Default([]) List parts, @Default([]) List files, - @Default([]) List chunks, @ThinkingThoughtRoleConverter() required ThinkingThoughtRole role, int? tokenCount, String? modelName, diff --git a/lib/models/thought.freezed.dart b/lib/models/thought.freezed.dart index f7696552..8ce76071 100644 --- a/lib/models/thought.freezed.dart +++ b/lib/models/thought.freezed.dart @@ -571,6 +571,846 @@ as Map?, } +/// @nodoc +mixin _$SnFunctionCall { + + String get id; String get name; String get arguments; +/// Create a copy of SnFunctionCall +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$SnFunctionCallCopyWith get copyWith => _$SnFunctionCallCopyWithImpl(this as SnFunctionCall, _$identity); + + /// Serializes this SnFunctionCall to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnFunctionCall&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.arguments, arguments) || other.arguments == arguments)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,name,arguments); + +@override +String toString() { + return 'SnFunctionCall(id: $id, name: $name, arguments: $arguments)'; +} + + +} + +/// @nodoc +abstract mixin class $SnFunctionCallCopyWith<$Res> { + factory $SnFunctionCallCopyWith(SnFunctionCall value, $Res Function(SnFunctionCall) _then) = _$SnFunctionCallCopyWithImpl; +@useResult +$Res call({ + String id, String name, String arguments +}); + + + + +} +/// @nodoc +class _$SnFunctionCallCopyWithImpl<$Res> + implements $SnFunctionCallCopyWith<$Res> { + _$SnFunctionCallCopyWithImpl(this._self, this._then); + + final SnFunctionCall _self; + final $Res Function(SnFunctionCall) _then; + +/// Create a copy of SnFunctionCall +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? arguments = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,arguments: null == arguments ? _self.arguments : arguments // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [SnFunctionCall]. +extension SnFunctionCallPatterns on SnFunctionCall { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _SnFunctionCall value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _SnFunctionCall() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _SnFunctionCall value) $default,){ +final _that = this; +switch (_that) { +case _SnFunctionCall(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SnFunctionCall value)? $default,){ +final _that = this; +switch (_that) { +case _SnFunctionCall() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String name, String arguments)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _SnFunctionCall() when $default != null: +return $default(_that.id,_that.name,_that.arguments);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String id, String name, String arguments) $default,) {final _that = this; +switch (_that) { +case _SnFunctionCall(): +return $default(_that.id,_that.name,_that.arguments);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String name, String arguments)? $default,) {final _that = this; +switch (_that) { +case _SnFunctionCall() when $default != null: +return $default(_that.id,_that.name,_that.arguments);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _SnFunctionCall implements SnFunctionCall { + const _SnFunctionCall({required this.id, required this.name, required this.arguments}); + factory _SnFunctionCall.fromJson(Map json) => _$SnFunctionCallFromJson(json); + +@override final String id; +@override final String name; +@override final String arguments; + +/// Create a copy of SnFunctionCall +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$SnFunctionCallCopyWith<_SnFunctionCall> get copyWith => __$SnFunctionCallCopyWithImpl<_SnFunctionCall>(this, _$identity); + +@override +Map toJson() { + return _$SnFunctionCallToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnFunctionCall&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.arguments, arguments) || other.arguments == arguments)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,name,arguments); + +@override +String toString() { + return 'SnFunctionCall(id: $id, name: $name, arguments: $arguments)'; +} + + +} + +/// @nodoc +abstract mixin class _$SnFunctionCallCopyWith<$Res> implements $SnFunctionCallCopyWith<$Res> { + factory _$SnFunctionCallCopyWith(_SnFunctionCall value, $Res Function(_SnFunctionCall) _then) = __$SnFunctionCallCopyWithImpl; +@override @useResult +$Res call({ + String id, String name, String arguments +}); + + + + +} +/// @nodoc +class __$SnFunctionCallCopyWithImpl<$Res> + implements _$SnFunctionCallCopyWith<$Res> { + __$SnFunctionCallCopyWithImpl(this._self, this._then); + + final _SnFunctionCall _self; + final $Res Function(_SnFunctionCall) _then; + +/// Create a copy of SnFunctionCall +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? arguments = null,}) { + return _then(_SnFunctionCall( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,arguments: null == arguments ? _self.arguments : arguments // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + + +/// @nodoc +mixin _$SnFunctionResult { + + String get callId; dynamic get result; bool get isError; +/// Create a copy of SnFunctionResult +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$SnFunctionResultCopyWith get copyWith => _$SnFunctionResultCopyWithImpl(this as SnFunctionResult, _$identity); + + /// Serializes this SnFunctionResult to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnFunctionResult&&(identical(other.callId, callId) || other.callId == callId)&&const DeepCollectionEquality().equals(other.result, result)&&(identical(other.isError, isError) || other.isError == isError)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,callId,const DeepCollectionEquality().hash(result),isError); + +@override +String toString() { + return 'SnFunctionResult(callId: $callId, result: $result, isError: $isError)'; +} + + +} + +/// @nodoc +abstract mixin class $SnFunctionResultCopyWith<$Res> { + factory $SnFunctionResultCopyWith(SnFunctionResult value, $Res Function(SnFunctionResult) _then) = _$SnFunctionResultCopyWithImpl; +@useResult +$Res call({ + String callId, dynamic result, bool isError +}); + + + + +} +/// @nodoc +class _$SnFunctionResultCopyWithImpl<$Res> + implements $SnFunctionResultCopyWith<$Res> { + _$SnFunctionResultCopyWithImpl(this._self, this._then); + + final SnFunctionResult _self; + final $Res Function(SnFunctionResult) _then; + +/// Create a copy of SnFunctionResult +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? callId = null,Object? result = freezed,Object? isError = null,}) { + return _then(_self.copyWith( +callId: null == callId ? _self.callId : callId // ignore: cast_nullable_to_non_nullable +as String,result: freezed == result ? _self.result : result // ignore: cast_nullable_to_non_nullable +as dynamic,isError: null == isError ? _self.isError : isError // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + +} + + +/// Adds pattern-matching-related methods to [SnFunctionResult]. +extension SnFunctionResultPatterns on SnFunctionResult { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _SnFunctionResult value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _SnFunctionResult() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _SnFunctionResult value) $default,){ +final _that = this; +switch (_that) { +case _SnFunctionResult(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SnFunctionResult value)? $default,){ +final _that = this; +switch (_that) { +case _SnFunctionResult() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String callId, dynamic result, bool isError)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _SnFunctionResult() when $default != null: +return $default(_that.callId,_that.result,_that.isError);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String callId, dynamic result, bool isError) $default,) {final _that = this; +switch (_that) { +case _SnFunctionResult(): +return $default(_that.callId,_that.result,_that.isError);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String callId, dynamic result, bool isError)? $default,) {final _that = this; +switch (_that) { +case _SnFunctionResult() when $default != null: +return $default(_that.callId,_that.result,_that.isError);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _SnFunctionResult implements SnFunctionResult { + const _SnFunctionResult({required this.callId, required this.result, required this.isError}); + factory _SnFunctionResult.fromJson(Map json) => _$SnFunctionResultFromJson(json); + +@override final String callId; +@override final dynamic result; +@override final bool isError; + +/// Create a copy of SnFunctionResult +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$SnFunctionResultCopyWith<_SnFunctionResult> get copyWith => __$SnFunctionResultCopyWithImpl<_SnFunctionResult>(this, _$identity); + +@override +Map toJson() { + return _$SnFunctionResultToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnFunctionResult&&(identical(other.callId, callId) || other.callId == callId)&&const DeepCollectionEquality().equals(other.result, result)&&(identical(other.isError, isError) || other.isError == isError)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,callId,const DeepCollectionEquality().hash(result),isError); + +@override +String toString() { + return 'SnFunctionResult(callId: $callId, result: $result, isError: $isError)'; +} + + +} + +/// @nodoc +abstract mixin class _$SnFunctionResultCopyWith<$Res> implements $SnFunctionResultCopyWith<$Res> { + factory _$SnFunctionResultCopyWith(_SnFunctionResult value, $Res Function(_SnFunctionResult) _then) = __$SnFunctionResultCopyWithImpl; +@override @useResult +$Res call({ + String callId, dynamic result, bool isError +}); + + + + +} +/// @nodoc +class __$SnFunctionResultCopyWithImpl<$Res> + implements _$SnFunctionResultCopyWith<$Res> { + __$SnFunctionResultCopyWithImpl(this._self, this._then); + + final _SnFunctionResult _self; + final $Res Function(_SnFunctionResult) _then; + +/// Create a copy of SnFunctionResult +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? callId = null,Object? result = freezed,Object? isError = null,}) { + return _then(_SnFunctionResult( +callId: null == callId ? _self.callId : callId // ignore: cast_nullable_to_non_nullable +as String,result: freezed == result ? _self.result : result // ignore: cast_nullable_to_non_nullable +as dynamic,isError: null == isError ? _self.isError : isError // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + + +} + + +/// @nodoc +mixin _$SnThinkingMessagePart { + +@ThinkingMessagePartTypeConverter() ThinkingMessagePartType get type; String? get text; SnFunctionCall? get functionCall; SnFunctionResult? get functionResult; +/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$SnThinkingMessagePartCopyWith get copyWith => _$SnThinkingMessagePartCopyWithImpl(this as SnThinkingMessagePart, _$identity); + + /// Serializes this SnThinkingMessagePart to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnThinkingMessagePart&&(identical(other.type, type) || other.type == type)&&(identical(other.text, text) || other.text == text)&&(identical(other.functionCall, functionCall) || other.functionCall == functionCall)&&(identical(other.functionResult, functionResult) || other.functionResult == functionResult)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,type,text,functionCall,functionResult); + +@override +String toString() { + return 'SnThinkingMessagePart(type: $type, text: $text, functionCall: $functionCall, functionResult: $functionResult)'; +} + + +} + +/// @nodoc +abstract mixin class $SnThinkingMessagePartCopyWith<$Res> { + factory $SnThinkingMessagePartCopyWith(SnThinkingMessagePart value, $Res Function(SnThinkingMessagePart) _then) = _$SnThinkingMessagePartCopyWithImpl; +@useResult +$Res call({ +@ThinkingMessagePartTypeConverter() ThinkingMessagePartType type, String? text, SnFunctionCall? functionCall, SnFunctionResult? functionResult +}); + + +$SnFunctionCallCopyWith<$Res>? get functionCall;$SnFunctionResultCopyWith<$Res>? get functionResult; + +} +/// @nodoc +class _$SnThinkingMessagePartCopyWithImpl<$Res> + implements $SnThinkingMessagePartCopyWith<$Res> { + _$SnThinkingMessagePartCopyWithImpl(this._self, this._then); + + final SnThinkingMessagePart _self; + final $Res Function(SnThinkingMessagePart) _then; + +/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? text = freezed,Object? functionCall = freezed,Object? functionResult = freezed,}) { + return _then(_self.copyWith( +type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as ThinkingMessagePartType,text: freezed == text ? _self.text : text // ignore: cast_nullable_to_non_nullable +as String?,functionCall: freezed == functionCall ? _self.functionCall : functionCall // ignore: cast_nullable_to_non_nullable +as SnFunctionCall?,functionResult: freezed == functionResult ? _self.functionResult : functionResult // ignore: cast_nullable_to_non_nullable +as SnFunctionResult?, + )); +} +/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnFunctionCallCopyWith<$Res>? get functionCall { + if (_self.functionCall == null) { + return null; + } + + return $SnFunctionCallCopyWith<$Res>(_self.functionCall!, (value) { + return _then(_self.copyWith(functionCall: value)); + }); +}/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnFunctionResultCopyWith<$Res>? get functionResult { + if (_self.functionResult == null) { + return null; + } + + return $SnFunctionResultCopyWith<$Res>(_self.functionResult!, (value) { + return _then(_self.copyWith(functionResult: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [SnThinkingMessagePart]. +extension SnThinkingMessagePartPatterns on SnThinkingMessagePart { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _SnThinkingMessagePart value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _SnThinkingMessagePart() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _SnThinkingMessagePart value) $default,){ +final _that = this; +switch (_that) { +case _SnThinkingMessagePart(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SnThinkingMessagePart value)? $default,){ +final _that = this; +switch (_that) { +case _SnThinkingMessagePart() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function(@ThinkingMessagePartTypeConverter() ThinkingMessagePartType type, String? text, SnFunctionCall? functionCall, SnFunctionResult? functionResult)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _SnThinkingMessagePart() when $default != null: +return $default(_that.type,_that.text,_that.functionCall,_that.functionResult);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function(@ThinkingMessagePartTypeConverter() ThinkingMessagePartType type, String? text, SnFunctionCall? functionCall, SnFunctionResult? functionResult) $default,) {final _that = this; +switch (_that) { +case _SnThinkingMessagePart(): +return $default(_that.type,_that.text,_that.functionCall,_that.functionResult);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function(@ThinkingMessagePartTypeConverter() ThinkingMessagePartType type, String? text, SnFunctionCall? functionCall, SnFunctionResult? functionResult)? $default,) {final _that = this; +switch (_that) { +case _SnThinkingMessagePart() when $default != null: +return $default(_that.type,_that.text,_that.functionCall,_that.functionResult);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _SnThinkingMessagePart implements SnThinkingMessagePart { + const _SnThinkingMessagePart({@ThinkingMessagePartTypeConverter() required this.type, this.text, this.functionCall, this.functionResult}); + factory _SnThinkingMessagePart.fromJson(Map json) => _$SnThinkingMessagePartFromJson(json); + +@override@ThinkingMessagePartTypeConverter() final ThinkingMessagePartType type; +@override final String? text; +@override final SnFunctionCall? functionCall; +@override final SnFunctionResult? functionResult; + +/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$SnThinkingMessagePartCopyWith<_SnThinkingMessagePart> get copyWith => __$SnThinkingMessagePartCopyWithImpl<_SnThinkingMessagePart>(this, _$identity); + +@override +Map toJson() { + return _$SnThinkingMessagePartToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnThinkingMessagePart&&(identical(other.type, type) || other.type == type)&&(identical(other.text, text) || other.text == text)&&(identical(other.functionCall, functionCall) || other.functionCall == functionCall)&&(identical(other.functionResult, functionResult) || other.functionResult == functionResult)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,type,text,functionCall,functionResult); + +@override +String toString() { + return 'SnThinkingMessagePart(type: $type, text: $text, functionCall: $functionCall, functionResult: $functionResult)'; +} + + +} + +/// @nodoc +abstract mixin class _$SnThinkingMessagePartCopyWith<$Res> implements $SnThinkingMessagePartCopyWith<$Res> { + factory _$SnThinkingMessagePartCopyWith(_SnThinkingMessagePart value, $Res Function(_SnThinkingMessagePart) _then) = __$SnThinkingMessagePartCopyWithImpl; +@override @useResult +$Res call({ +@ThinkingMessagePartTypeConverter() ThinkingMessagePartType type, String? text, SnFunctionCall? functionCall, SnFunctionResult? functionResult +}); + + +@override $SnFunctionCallCopyWith<$Res>? get functionCall;@override $SnFunctionResultCopyWith<$Res>? get functionResult; + +} +/// @nodoc +class __$SnThinkingMessagePartCopyWithImpl<$Res> + implements _$SnThinkingMessagePartCopyWith<$Res> { + __$SnThinkingMessagePartCopyWithImpl(this._self, this._then); + + final _SnThinkingMessagePart _self; + final $Res Function(_SnThinkingMessagePart) _then; + +/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? text = freezed,Object? functionCall = freezed,Object? functionResult = freezed,}) { + return _then(_SnThinkingMessagePart( +type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as ThinkingMessagePartType,text: freezed == text ? _self.text : text // ignore: cast_nullable_to_non_nullable +as String?,functionCall: freezed == functionCall ? _self.functionCall : functionCall // ignore: cast_nullable_to_non_nullable +as SnFunctionCall?,functionResult: freezed == functionResult ? _self.functionResult : functionResult // ignore: cast_nullable_to_non_nullable +as SnFunctionResult?, + )); +} + +/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnFunctionCallCopyWith<$Res>? get functionCall { + if (_self.functionCall == null) { + return null; + } + + return $SnFunctionCallCopyWith<$Res>(_self.functionCall!, (value) { + return _then(_self.copyWith(functionCall: value)); + }); +}/// Create a copy of SnThinkingMessagePart +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnFunctionResultCopyWith<$Res>? get functionResult { + if (_self.functionResult == null) { + return null; + } + + return $SnFunctionResultCopyWith<$Res>(_self.functionResult!, (value) { + return _then(_self.copyWith(functionResult: value)); + }); +} +} + + /// @nodoc mixin _$SnThinkingSequence { @@ -852,7 +1692,7 @@ as DateTime?, /// @nodoc mixin _$SnThinkingThought { - String get id; String? get content; List get files; List get chunks;@ThinkingThoughtRoleConverter() ThinkingThoughtRole get role; int? get tokenCount; String? get modelName; String get sequenceId; SnThinkingSequence? get sequence; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; + String get id; List get parts; List get files;@ThinkingThoughtRoleConverter() ThinkingThoughtRole get role; int? get tokenCount; String? get modelName; String get sequenceId; SnThinkingSequence? get sequence; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; /// Create a copy of SnThinkingThought /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -865,16 +1705,16 @@ $SnThinkingThoughtCopyWith get copyWith => _$SnThinkingThough @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is SnThinkingThought&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&const DeepCollectionEquality().equals(other.files, files)&&const DeepCollectionEquality().equals(other.chunks, chunks)&&(identical(other.role, role) || other.role == role)&&(identical(other.tokenCount, tokenCount) || other.tokenCount == tokenCount)&&(identical(other.modelName, modelName) || other.modelName == modelName)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnThinkingThought&&(identical(other.id, id) || other.id == id)&&const DeepCollectionEquality().equals(other.parts, parts)&&const DeepCollectionEquality().equals(other.files, files)&&(identical(other.role, role) || other.role == role)&&(identical(other.tokenCount, tokenCount) || other.tokenCount == tokenCount)&&(identical(other.modelName, modelName) || other.modelName == modelName)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,content,const DeepCollectionEquality().hash(files),const DeepCollectionEquality().hash(chunks),role,tokenCount,modelName,sequenceId,sequence,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,const DeepCollectionEquality().hash(parts),const DeepCollectionEquality().hash(files),role,tokenCount,modelName,sequenceId,sequence,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnThinkingThought(id: $id, content: $content, files: $files, chunks: $chunks, role: $role, tokenCount: $tokenCount, modelName: $modelName, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnThinkingThought(id: $id, parts: $parts, files: $files, role: $role, tokenCount: $tokenCount, modelName: $modelName, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -885,7 +1725,7 @@ abstract mixin class $SnThinkingThoughtCopyWith<$Res> { factory $SnThinkingThoughtCopyWith(SnThinkingThought value, $Res Function(SnThinkingThought) _then) = _$SnThinkingThoughtCopyWithImpl; @useResult $Res call({ - String id, String? content, List files, List chunks,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, List parts, List files,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); @@ -902,13 +1742,12 @@ class _$SnThinkingThoughtCopyWithImpl<$Res> /// Create a copy of SnThinkingThought /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? content = freezed,Object? files = null,Object? chunks = null,Object? role = null,Object? tokenCount = freezed,Object? modelName = freezed,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? parts = null,Object? files = null,Object? role = null,Object? tokenCount = freezed,Object? modelName = freezed,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable -as String,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable -as String?,files: null == files ? _self.files : files // ignore: cast_nullable_to_non_nullable -as List,chunks: null == chunks ? _self.chunks : chunks // ignore: cast_nullable_to_non_nullable -as List,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as String,parts: null == parts ? _self.parts : parts // ignore: cast_nullable_to_non_nullable +as List,files: null == files ? _self.files : files // ignore: cast_nullable_to_non_nullable +as List,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable as ThinkingThoughtRole,tokenCount: freezed == tokenCount ? _self.tokenCount : tokenCount // ignore: cast_nullable_to_non_nullable as int?,modelName: freezed == modelName ? _self.modelName : modelName // ignore: cast_nullable_to_non_nullable as String?,sequenceId: null == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable @@ -1010,10 +1849,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, List parts, List files, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _SnThinkingThought() when $default != null: -return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.parts,_that.files,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return orElse(); } @@ -1031,10 +1870,10 @@ return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, List parts, List files, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; switch (_that) { case _SnThinkingThought(): -return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);} +return $default(_that.id,_that.parts,_that.files,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);} } /// A variant of `when` that fallback to returning `null` /// @@ -1048,10 +1887,10 @@ return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, List parts, List files, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; switch (_that) { case _SnThinkingThought() when $default != null: -return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.parts,_that.files,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return null; } @@ -1063,11 +1902,17 @@ return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that @JsonSerializable() class _SnThinkingThought implements SnThinkingThought { - const _SnThinkingThought({required this.id, this.content, final List files = const [], final List chunks = const [], @ThinkingThoughtRoleConverter() required this.role, this.tokenCount, this.modelName, required this.sequenceId, this.sequence, required this.createdAt, required this.updatedAt, this.deletedAt}): _files = files,_chunks = chunks; + const _SnThinkingThought({required this.id, final List parts = const [], final List files = const [], @ThinkingThoughtRoleConverter() required this.role, this.tokenCount, this.modelName, required this.sequenceId, this.sequence, required this.createdAt, required this.updatedAt, this.deletedAt}): _parts = parts,_files = files; factory _SnThinkingThought.fromJson(Map json) => _$SnThinkingThoughtFromJson(json); @override final String id; -@override final String? content; + final List _parts; +@override@JsonKey() List get parts { + if (_parts is EqualUnmodifiableListView) return _parts; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_parts); +} + final List _files; @override@JsonKey() List get files { if (_files is EqualUnmodifiableListView) return _files; @@ -1075,13 +1920,6 @@ class _SnThinkingThought implements SnThinkingThought { return EqualUnmodifiableListView(_files); } - final List _chunks; -@override@JsonKey() List get chunks { - if (_chunks is EqualUnmodifiableListView) return _chunks; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_chunks); -} - @override@ThinkingThoughtRoleConverter() final ThinkingThoughtRole role; @override final int? tokenCount; @override final String? modelName; @@ -1104,16 +1942,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnThinkingThought&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&const DeepCollectionEquality().equals(other._files, _files)&&const DeepCollectionEquality().equals(other._chunks, _chunks)&&(identical(other.role, role) || other.role == role)&&(identical(other.tokenCount, tokenCount) || other.tokenCount == tokenCount)&&(identical(other.modelName, modelName) || other.modelName == modelName)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnThinkingThought&&(identical(other.id, id) || other.id == id)&&const DeepCollectionEquality().equals(other._parts, _parts)&&const DeepCollectionEquality().equals(other._files, _files)&&(identical(other.role, role) || other.role == role)&&(identical(other.tokenCount, tokenCount) || other.tokenCount == tokenCount)&&(identical(other.modelName, modelName) || other.modelName == modelName)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,content,const DeepCollectionEquality().hash(_files),const DeepCollectionEquality().hash(_chunks),role,tokenCount,modelName,sequenceId,sequence,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,const DeepCollectionEquality().hash(_parts),const DeepCollectionEquality().hash(_files),role,tokenCount,modelName,sequenceId,sequence,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnThinkingThought(id: $id, content: $content, files: $files, chunks: $chunks, role: $role, tokenCount: $tokenCount, modelName: $modelName, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnThinkingThought(id: $id, parts: $parts, files: $files, role: $role, tokenCount: $tokenCount, modelName: $modelName, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -1124,7 +1962,7 @@ abstract mixin class _$SnThinkingThoughtCopyWith<$Res> implements $SnThinkingTho factory _$SnThinkingThoughtCopyWith(_SnThinkingThought value, $Res Function(_SnThinkingThought) _then) = __$SnThinkingThoughtCopyWithImpl; @override @useResult $Res call({ - String id, String? content, List files, List chunks,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, List parts, List files,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); @@ -1141,13 +1979,12 @@ class __$SnThinkingThoughtCopyWithImpl<$Res> /// Create a copy of SnThinkingThought /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? content = freezed,Object? files = null,Object? chunks = null,Object? role = null,Object? tokenCount = freezed,Object? modelName = freezed,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? parts = null,Object? files = null,Object? role = null,Object? tokenCount = freezed,Object? modelName = freezed,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_SnThinkingThought( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable -as String,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable -as String?,files: null == files ? _self._files : files // ignore: cast_nullable_to_non_nullable -as List,chunks: null == chunks ? _self._chunks : chunks // ignore: cast_nullable_to_non_nullable -as List,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as String,parts: null == parts ? _self._parts : parts // ignore: cast_nullable_to_non_nullable +as List,files: null == files ? _self._files : files // ignore: cast_nullable_to_non_nullable +as List,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable as ThinkingThoughtRole,tokenCount: freezed == tokenCount ? _self.tokenCount : tokenCount // ignore: cast_nullable_to_non_nullable as int?,modelName: freezed == modelName ? _self.modelName : modelName // ignore: cast_nullable_to_non_nullable as String?,sequenceId: null == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable diff --git a/lib/models/thought.g.dart b/lib/models/thought.g.dart index 4ac2ae65..5778060e 100644 --- a/lib/models/thought.g.dart +++ b/lib/models/thought.g.dart @@ -50,6 +50,64 @@ Map _$SnThinkingChunkToJson(_SnThinkingChunk instance) => 'data': instance.data, }; +_SnFunctionCall _$SnFunctionCallFromJson(Map json) => + _SnFunctionCall( + id: json['id'] as String, + name: json['name'] as String, + arguments: json['arguments'] as String, + ); + +Map _$SnFunctionCallToJson(_SnFunctionCall instance) => + { + 'id': instance.id, + 'name': instance.name, + 'arguments': instance.arguments, + }; + +_SnFunctionResult _$SnFunctionResultFromJson(Map json) => + _SnFunctionResult( + callId: json['call_id'] as String, + result: json['result'], + isError: json['is_error'] as bool, + ); + +Map _$SnFunctionResultToJson(_SnFunctionResult instance) => + { + 'call_id': instance.callId, + 'result': instance.result, + 'is_error': instance.isError, + }; + +_SnThinkingMessagePart _$SnThinkingMessagePartFromJson( + Map json, +) => _SnThinkingMessagePart( + type: const ThinkingMessagePartTypeConverter().fromJson( + (json['type'] as num).toInt(), + ), + text: json['text'] as String?, + functionCall: + json['function_call'] == null + ? null + : SnFunctionCall.fromJson( + json['function_call'] as Map, + ), + functionResult: + json['function_result'] == null + ? null + : SnFunctionResult.fromJson( + json['function_result'] as Map, + ), +); + +Map _$SnThinkingMessagePartToJson( + _SnThinkingMessagePart instance, +) => { + 'type': const ThinkingMessagePartTypeConverter().toJson(instance.type), + 'text': instance.text, + 'function_call': instance.functionCall?.toJson(), + 'function_result': instance.functionResult?.toJson(), +}; + _SnThinkingSequence _$SnThinkingSequenceFromJson(Map json) => _SnThinkingSequence( id: json['id'] as String, @@ -80,17 +138,19 @@ Map _$SnThinkingSequenceToJson(_SnThinkingSequence instance) => _SnThinkingThought _$SnThinkingThoughtFromJson(Map json) => _SnThinkingThought( id: json['id'] as String, - content: json['content'] as String?, + parts: + (json['parts'] as List?) + ?.map( + (e) => + SnThinkingMessagePart.fromJson(e as Map), + ) + .toList() ?? + const [], files: (json['files'] as List?) ?.map((e) => SnCloudFile.fromJson(e as Map)) .toList() ?? const [], - chunks: - (json['chunks'] as List?) - ?.map((e) => SnThinkingChunk.fromJson(e as Map)) - .toList() ?? - const [], role: const ThinkingThoughtRoleConverter().fromJson( (json['role'] as num).toInt(), ), @@ -114,9 +174,8 @@ _SnThinkingThought _$SnThinkingThoughtFromJson(Map json) => Map _$SnThinkingThoughtToJson(_SnThinkingThought instance) => { 'id': instance.id, - 'content': instance.content, + 'parts': instance.parts.map((e) => e.toJson()).toList(), 'files': instance.files.map((e) => e.toJson()).toList(), - 'chunks': instance.chunks.map((e) => e.toJson()).toList(), 'role': const ThinkingThoughtRoleConverter().toJson(instance.role), 'token_count': instance.tokenCount, 'model_name': instance.modelName, diff --git a/lib/screens/thought/think.dart b/lib/screens/thought/think.dart index 0a2b847c..259fba77 100644 --- a/lib/screens/thought/think.dart +++ b/lib/screens/thought/think.dart @@ -10,7 +10,6 @@ import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:island/models/thought.dart"; import "package:island/pods/network.dart"; import "package:island/pods/userinfo.dart"; -import "package:island/widgets/alert.dart"; import "package:island/widgets/app_scaffold.dart"; import "package:island/widgets/response.dart"; import "package:island/widgets/thought/thought_sequence_list.dart"; @@ -52,8 +51,7 @@ class ThoughtScreen extends HookConsumerWidget { final messageController = useTextEditingController(); final scrollController = useScrollController(); final isStreaming = useState(false); - final streamingText = useState(''); - final functionCalls = useState>([]); + final streamingParts = useState>([]); final reasoningChunks = useState>([]); final listController = useMemoized(() => ListController(), []); @@ -114,7 +112,12 @@ class ThoughtScreen extends HookConsumerWidget { final now = DateTime.now(); final userThought = SnThinkingThought( id: 'user-${DateTime.now().millisecondsSinceEpoch}', - content: userMessage, + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: userMessage, + ), + ], files: [], role: ThinkingThoughtRole.user, sequenceId: selectedSequenceId.value ?? '', @@ -148,8 +151,7 @@ class ThoughtScreen extends HookConsumerWidget { try { isStreaming.value = true; - streamingText.value = ''; - functionCalls.value = []; + streamingParts.value = []; reasoningChunks.value = []; final apiClient = ref.read(apiClientProvider); @@ -183,11 +185,39 @@ class ThoughtScreen extends HookConsumerWidget { final type = event['type']; final eventData = event['data']; if (type == 'text') { - streamingText.value += eventData; + if (streamingParts.value.isNotEmpty && + streamingParts.value.last.type == + ThinkingMessagePartType.text) { + final last = streamingParts.value.last; + final newParts = [...streamingParts.value]; + newParts[newParts.length - 1] = last.copyWith( + text: (last.text ?? '') + eventData, + ); + streamingParts.value = newParts; + } else { + streamingParts.value = [ + ...streamingParts.value, + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: eventData, + ), + ]; + } } else if (type == 'function_call') { - functionCalls.value = [ - ...functionCalls.value, - JsonEncoder.withIndent(' ').convert(eventData), + streamingParts.value = [ + ...streamingParts.value, + SnThinkingMessagePart( + type: ThinkingMessagePartType.functionCall, + functionCall: SnFunctionCall.fromJson(eventData), + ), + ]; + } else if (type == 'function_result') { + streamingParts.value = [ + ...streamingParts.value, + SnThinkingMessagePart( + type: ThinkingMessagePartType.functionResult, + functionResult: SnFunctionResult.fromJson(eventData), + ), ]; } else if (type == 'reasoning') { reasoningChunks.value = [ @@ -218,16 +248,61 @@ class ThoughtScreen extends HookConsumerWidget { onDone: () { if (isStreaming.value) { isStreaming.value = false; - showErrorAlert('thoughtParseError'.tr()); + // Add error thought to the list for incomplete response + final now = DateTime.now(); + final errorThought = SnThinkingThought( + id: 'error-${DateTime.now().millisecondsSinceEpoch}', + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: 'Error: ${'thoughtParseError'.tr()}', + ), + ], + files: [], + role: ThinkingThoughtRole.assistant, + sequenceId: selectedSequenceId.value ?? '', + createdAt: now, + updatedAt: now, + sequence: SnThinkingSequence( + id: selectedSequenceId.value ?? '', + accountId: '', + createdAt: now, + updatedAt: now, + ), + ); + localThoughts.value = [errorThought, ...localThoughts.value]; } }, onError: (error) { isStreaming.value = false; - if (error is DioException && error.response?.data is ResponseBody) { - showErrorAlert('toughtParseError'.tr()); - } else { - showErrorAlert(error); - } + + // Add error thought to the list + final now = DateTime.now(); + final errorMessage = + error is DioException && error.response?.data is ResponseBody + ? 'toughtParseError'.tr() + : error.toString(); + final errorThought = SnThinkingThought( + id: 'error-${DateTime.now().millisecondsSinceEpoch}', + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: 'Error: $errorMessage', + ), + ], + files: [], + role: ThinkingThoughtRole.assistant, + sequenceId: selectedSequenceId.value ?? '', + createdAt: now, + updatedAt: now, + sequence: SnThinkingSequence( + id: selectedSequenceId.value ?? '', + accountId: '', + createdAt: now, + updatedAt: now, + ), + ); + localThoughts.value = [errorThought, ...localThoughts.value]; }, ); @@ -235,7 +310,32 @@ class ThoughtScreen extends HookConsumerWidget { FocusManager.instance.primaryFocus?.unfocus(); } catch (error) { isStreaming.value = false; - showErrorAlert(error); + + // Add error thought to the list for initial request errors + final now = DateTime.now(); + final userInfo = ref.read(userInfoProvider); + final errorMessage = error.toString(); + final errorThought = SnThinkingThought( + id: 'error-${DateTime.now().millisecondsSinceEpoch}', + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: 'Error: $errorMessage', + ), + ], + files: [], + role: ThinkingThoughtRole.assistant, + sequenceId: selectedSequenceId.value ?? '', + createdAt: now, + updatedAt: now, + sequence: SnThinkingSequence( + id: selectedSequenceId.value ?? '', + accountId: userInfo.value!.id, + createdAt: now, + updatedAt: now, + ), + ); + localThoughts.value = [errorThought, ...localThoughts.value]; } } @@ -302,11 +402,36 @@ class ThoughtScreen extends HookConsumerWidget { (isStreaming.value ? 1 : 0), itemBuilder: (context, index) { if (isStreaming.value && index == 0) { + final streamingText = streamingParts.value + .where( + (p) => + p.type == + ThinkingMessagePartType.text, + ) + .map((p) => p.text ?? '') + .join(''); + final streamingFunctionCalls = + streamingParts.value + .where( + (p) => + p.type == + ThinkingMessagePartType + .functionCall, + ) + .map( + (p) => JsonEncoder.withIndent( + ' ', + ).convert( + p.functionCall?.toJson() ?? {}, + ), + ) + .toList(); return ThoughtItem( isStreaming: true, - streamingText: streamingText.value, + streamingText: streamingText, reasoningChunks: reasoningChunks.value, - streamingFunctionCalls: functionCalls.value, + streamingFunctionCalls: + streamingFunctionCalls, ); } final thoughtIndex = diff --git a/lib/screens/thought/think_sheet.dart b/lib/screens/thought/think_sheet.dart index 84d52eae..6e1cac84 100644 --- a/lib/screens/thought/think_sheet.dart +++ b/lib/screens/thought/think_sheet.dart @@ -8,7 +8,6 @@ import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:island/models/thought.dart"; import "package:island/pods/network.dart"; import "package:island/pods/userinfo.dart"; -import "package:island/widgets/alert.dart"; import "package:island/widgets/content/sheet.dart"; import "package:island/widgets/thought/thought_shared.dart"; import "package:super_sliver_list/super_sliver_list.dart"; @@ -49,8 +48,7 @@ class ThoughtSheet extends HookConsumerWidget { final messageController = useTextEditingController(); final scrollController = useScrollController(); final isStreaming = useState(false); - final streamingText = useState(''); - final functionCalls = useState>([]); + final streamingParts = useState>([]); final reasoningChunks = useState>([]); final listController = useMemoized(() => ListController(), []); @@ -96,7 +94,12 @@ class ThoughtSheet extends HookConsumerWidget { final now = DateTime.now(); final userThought = SnThinkingThought( id: 'user-${DateTime.now().millisecondsSinceEpoch}', - content: userMessage, + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: userMessage, + ), + ], files: [], role: ThinkingThoughtRole.user, sequenceId: sequenceId.value ?? '', @@ -121,8 +124,7 @@ class ThoughtSheet extends HookConsumerWidget { try { isStreaming.value = true; - streamingText.value = ''; - functionCalls.value = []; + streamingParts.value = []; reasoningChunks.value = []; final apiClient = ref.read(apiClientProvider); @@ -156,11 +158,39 @@ class ThoughtSheet extends HookConsumerWidget { final type = event['type']; final eventData = event['data']; if (type == 'text') { - streamingText.value += eventData; + if (streamingParts.value.isNotEmpty && + streamingParts.value.last.type == + ThinkingMessagePartType.text) { + final last = streamingParts.value.last; + final newParts = [...streamingParts.value]; + newParts[newParts.length - 1] = last.copyWith( + text: (last.text ?? '') + eventData, + ); + streamingParts.value = newParts; + } else { + streamingParts.value = [ + ...streamingParts.value, + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: eventData, + ), + ]; + } } else if (type == 'function_call') { - functionCalls.value = [ - ...functionCalls.value, - JsonEncoder.withIndent(' ').convert(eventData), + streamingParts.value = [ + ...streamingParts.value, + SnThinkingMessagePart( + type: ThinkingMessagePartType.functionCall, + functionCall: SnFunctionCall.fromJson(eventData), + ), + ]; + } else if (type == 'function_result') { + streamingParts.value = [ + ...streamingParts.value, + SnThinkingMessagePart( + type: ThinkingMessagePartType.functionResult, + functionResult: SnFunctionResult.fromJson(eventData), + ), ]; } else if (type == 'reasoning') { reasoningChunks.value = [ @@ -191,16 +221,63 @@ class ThoughtSheet extends HookConsumerWidget { onDone: () { if (isStreaming.value) { isStreaming.value = false; - showErrorAlert('thoughtParseError'.tr()); + // Add error thought to the list for incomplete response + final userInfo = ref.read(userInfoProvider); + final now = DateTime.now(); + final errorThought = SnThinkingThought( + id: 'error-${DateTime.now().millisecondsSinceEpoch}', + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: 'Error: ${'thoughtParseError'.tr()}', + ), + ], + files: [], + role: ThinkingThoughtRole.assistant, + sequenceId: sequenceId.value ?? '', + createdAt: now, + updatedAt: now, + sequence: SnThinkingSequence( + id: sequenceId.value ?? '', + accountId: userInfo.value!.id, + createdAt: now, + updatedAt: now, + ), + ); + localThoughts.value = [errorThought, ...localThoughts.value]; } }, onError: (error) { isStreaming.value = false; - if (error is DioException && error.response?.data is ResponseBody) { - showErrorAlert('toughtParseError'.tr()); - } else { - showErrorAlert(error); - } + + // Add error thought to the list + final userInfo = ref.read(userInfoProvider); + final now = DateTime.now(); + final errorMessage = + error is DioException && error.response?.data is ResponseBody + ? 'toughtParseError'.tr() + : error.toString(); + final errorThought = SnThinkingThought( + id: 'error-${DateTime.now().millisecondsSinceEpoch}', + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: 'Error: $errorMessage', + ), + ], + files: [], + role: ThinkingThoughtRole.assistant, + sequenceId: sequenceId.value ?? '', + createdAt: now, + updatedAt: now, + sequence: SnThinkingSequence( + id: sequenceId.value ?? '', + accountId: userInfo.value!.id, + createdAt: now, + updatedAt: now, + ), + ); + localThoughts.value = [errorThought, ...localThoughts.value]; }, ); @@ -208,7 +285,32 @@ class ThoughtSheet extends HookConsumerWidget { FocusManager.instance.primaryFocus?.unfocus(); } catch (error) { isStreaming.value = false; - showErrorAlert(error); + + // Add error thought to the list for initial request errors + final userInfo = ref.read(userInfoProvider); + final now = DateTime.now(); + final errorMessage = error.toString(); + final errorThought = SnThinkingThought( + id: 'error-${DateTime.now().millisecondsSinceEpoch}', + parts: [ + SnThinkingMessagePart( + type: ThinkingMessagePartType.text, + text: 'Error: $errorMessage', + ), + ], + files: [], + role: ThinkingThoughtRole.assistant, + sequenceId: sequenceId.value ?? '', + createdAt: now, + updatedAt: now, + sequence: SnThinkingSequence( + id: sequenceId.value ?? '', + accountId: userInfo.value!.id, + createdAt: now, + updatedAt: now, + ), + ); + localThoughts.value = [errorThought, ...localThoughts.value]; } } @@ -238,11 +340,30 @@ class ThoughtSheet extends HookConsumerWidget { (isStreaming.value ? 1 : 0), itemBuilder: (context, index) { if (isStreaming.value && index == 0) { + final streamingText = streamingParts.value + .where( + (p) => p.type == ThinkingMessagePartType.text, + ) + .map((p) => p.text ?? '') + .join(''); + final streamingFunctionCalls = + streamingParts.value + .where( + (p) => + p.type == + ThinkingMessagePartType.functionCall, + ) + .map( + (p) => JsonEncoder.withIndent( + ' ', + ).convert(p.functionCall?.toJson() ?? {}), + ) + .toList(); return ThoughtItem( isStreaming: true, - streamingText: streamingText.value, + streamingText: streamingText, reasoningChunks: reasoningChunks.value, - streamingFunctionCalls: functionCalls.value, + streamingFunctionCalls: streamingFunctionCalls, ); } final thoughtIndex = diff --git a/lib/widgets/thought/function_calls_section.dart b/lib/widgets/thought/function_calls_section.dart index aad4a6ac..06f85e52 100644 --- a/lib/widgets/thought/function_calls_section.dart +++ b/lib/widgets/thought/function_calls_section.dart @@ -30,9 +30,9 @@ class _FunctionCallsSectionState extends State { if (widget.isStreaming) { return widget.streamingFunctionCalls.isNotEmpty; } else { - return widget.thought!.chunks.isNotEmpty && - widget.thought!.chunks.any( - (chunk) => chunk.type == ThinkingChunkType.functionCall, + return widget.thought!.parts.isNotEmpty && + widget.thought!.parts.any( + (part) => part.type == ThinkingMessagePartType.functionCall, ); } } @@ -115,13 +115,14 @@ class _FunctionCallsSectionState extends State { ), ), ] else ...[ - ...widget.thought!.chunks + ...widget.thought!.parts .where( - (chunk) => - chunk.type == ThinkingChunkType.functionCall, + (part) => + part.type == + ThinkingMessagePartType.functionCall, ) .map( - (chunk) => Container( + (part) => Container( width: double.infinity, padding: const EdgeInsets.all(8), margin: const EdgeInsets.only(bottom: 4), @@ -138,7 +139,7 @@ class _FunctionCallsSectionState extends State { child: SelectableText( JsonEncoder.withIndent( ' ', - ).convert(chunk.data), + ).convert(part.functionCall?.toJson() ?? {}), style: GoogleFonts.robotoMono( fontSize: 11, color: diff --git a/lib/widgets/thought/thought_content.dart b/lib/widgets/thought/thought_content.dart index 589a3665..e09a59db 100644 --- a/lib/widgets/thought/thought_content.dart +++ b/lib/widgets/thought/thought_content.dart @@ -15,29 +15,62 @@ class ThoughtContent extends StatelessWidget { final String streamingText; final SnThinkingThought? thought; + bool get _isErrorMessage { + if (thought == null) return false; + // Check if this is an error thought by ID or content + if (thought!.id.startsWith('error-')) return true; + final textParts = thought!.parts + .where((p) => p.type == ThinkingMessagePartType.text) + .map((p) => p.text ?? '') + .join(''); + return textParts.startsWith('Error:'); + } + @override Widget build(BuildContext context) { if (isStreaming) { // Streaming text with spinner if (streamingText.isNotEmpty) { + final isStreamingError = streamingText.startsWith('Error:'); return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: MarkdownTextContent( - isSelectable: true, - content: streamingText, - extraBlockSyntaxList: [ProposalBlockSyntax()], - textStyle: Theme.of(context).textTheme.bodyMedium, - extraGenerators: [ - ProposalGenerator( - backgroundColor: - Theme.of(context).colorScheme.secondaryContainer, - foregroundColor: - Theme.of(context).colorScheme.onSecondaryContainer, - borderColor: Theme.of(context).colorScheme.outline, + child: Container( + padding: + isStreamingError + ? const EdgeInsets.all(8) + : EdgeInsets.zero, + decoration: + isStreamingError + ? BoxDecoration( + border: Border.all( + color: Theme.of(context).colorScheme.error, + width: 1, + ), + borderRadius: BorderRadius.circular(8), + ) + : null, + child: MarkdownTextContent( + isSelectable: true, + content: streamingText, + extraBlockSyntaxList: [ProposalBlockSyntax()], + textStyle: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: + isStreamingError + ? Theme.of(context).colorScheme.error + : null, ), - ], + extraGenerators: [ + ProposalGenerator( + backgroundColor: + Theme.of(context).colorScheme.secondaryContainer, + foregroundColor: + Theme.of(context).colorScheme.onSecondaryContainer, + borderColor: Theme.of(context).colorScheme.outline, + ), + ], + ), ), ), const SizedBox(width: 8), @@ -56,22 +89,53 @@ class ThoughtContent extends StatelessWidget { } return const SizedBox.shrink(); } else { - // Regular thought content - if (thought!.content != null && thought!.content!.isNotEmpty) { - return MarkdownTextContent( - isSelectable: true, - content: thought!.content!, - extraBlockSyntaxList: [ProposalBlockSyntax()], - textStyle: Theme.of(context).textTheme.bodyMedium, - extraGenerators: [ - ProposalGenerator( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, - foregroundColor: - Theme.of(context).colorScheme.onSecondaryContainer, - borderColor: Theme.of(context).colorScheme.outline, + // Regular thought content - render parts + if (thought!.parts.isNotEmpty) { + final textParts = thought!.parts + .where((p) => p.type == ThinkingMessagePartType.text) + .map((p) => p.text ?? '') + .join(''); + if (textParts.isNotEmpty) { + return Container( + padding: + _isErrorMessage + ? const EdgeInsets.symmetric(horizontal: 12, vertical: 4) + : EdgeInsets.zero, + decoration: + _isErrorMessage + ? BoxDecoration( + color: Theme.of( + context, + ).colorScheme.error.withOpacity(0.1), + border: Border.all( + color: Theme.of(context).colorScheme.error, + width: 1, + ), + borderRadius: BorderRadius.circular(8), + ) + : null, + child: MarkdownTextContent( + isSelectable: true, + content: textParts, + extraBlockSyntaxList: [ProposalBlockSyntax()], + textStyle: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: + _isErrorMessage + ? Theme.of(context).colorScheme.error + : null, + ), + extraGenerators: [ + ProposalGenerator( + backgroundColor: + Theme.of(context).colorScheme.secondaryContainer, + foregroundColor: + Theme.of(context).colorScheme.onSecondaryContainer, + borderColor: Theme.of(context).colorScheme.outline, + ), + ], ), - ], - ); + ); + } } return const SizedBox.shrink(); } diff --git a/lib/widgets/thought/thought_shared.dart b/lib/widgets/thought/thought_shared.dart index ba936177..117e2d5b 100644 --- a/lib/widgets/thought/thought_shared.dart +++ b/lib/widgets/thought/thought_shared.dart @@ -211,8 +211,13 @@ class ThoughtItem extends StatelessWidget { (!isStreaming && thought!.role == ThinkingThoughtRole.assistant); final List> proposals = - !isStreaming && thought!.content != null - ? _extractProposals(thought!.content!) + !isStreaming + ? _extractProposals( + thought!.parts + .where((p) => p.type == ThinkingMessagePartType.text) + .map((p) => p.text ?? '') + .join(''), + ) : []; return Container( @@ -251,10 +256,10 @@ class ThoughtItem extends StatelessWidget { // Function calls if (streamingFunctionCalls.isNotEmpty || - (thought?.chunks.isNotEmpty ?? false) && - thought!.chunks.any( - (chunk) => - chunk.type == ThinkingChunkType.functionCall, + (thought?.parts.isNotEmpty ?? false) && + thought!.parts.any( + (part) => + part.type == ThinkingMessagePartType.functionCall, )) FunctionCallsSection( isStreaming: isStreaming,