@@ -404,18 +404,47 @@ class SocketConnectionStream extends _$SocketConnectionStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
Stream<ConversationDelta> conversationDeltaStream(
|
class ConversationDeltaStream extends _$ConversationDeltaStream {
|
||||||
Ref ref,
|
StreamController<ConversationDelta>? _controller;
|
||||||
ConversationDeltaRequest request,
|
ProviderSubscription<AsyncValue<SocketService?>>? _serviceSubscription;
|
||||||
) {
|
SocketEventSubscription? _socketSubscription;
|
||||||
final controller = StreamController<ConversationDelta>.broadcast(sync: true);
|
|
||||||
|
|
||||||
ProviderSubscription<AsyncValue<SocketService?>>? serviceSubscription;
|
@override
|
||||||
SocketEventSubscription? socketSubscription;
|
Stream<ConversationDelta> build(ConversationDeltaRequest request) {
|
||||||
|
final controller = StreamController<ConversationDelta>.broadcast(
|
||||||
|
sync: true,
|
||||||
|
onCancel: _maybeTearDownSocket,
|
||||||
|
);
|
||||||
|
_controller = controller;
|
||||||
|
|
||||||
void bindSocket(SocketService? service) {
|
final initialService = ref
|
||||||
socketSubscription?.dispose();
|
.watch(socketServiceManagerProvider)
|
||||||
socketSubscription = null;
|
.maybeWhen(data: (service) => service, orElse: () => null);
|
||||||
|
_bindSocket(initialService, request);
|
||||||
|
|
||||||
|
_serviceSubscription = ref.listen<AsyncValue<SocketService?>>(
|
||||||
|
socketServiceManagerProvider,
|
||||||
|
(_, next) => _bindSocket(
|
||||||
|
next.maybeWhen(data: (service) => service, orElse: () => null),
|
||||||
|
request,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
ref.onDispose(() {
|
||||||
|
_serviceSubscription?.close();
|
||||||
|
_serviceSubscription = null;
|
||||||
|
_socketSubscription?.dispose();
|
||||||
|
_socketSubscription = null;
|
||||||
|
_controller?.close();
|
||||||
|
_controller = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return controller.stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _bindSocket(SocketService? service, ConversationDeltaRequest request) {
|
||||||
|
_socketSubscription?.dispose();
|
||||||
|
_socketSubscription = null;
|
||||||
|
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
return;
|
return;
|
||||||
@@ -423,65 +452,68 @@ Stream<ConversationDelta> conversationDeltaStream(
|
|||||||
|
|
||||||
switch (request.source) {
|
switch (request.source) {
|
||||||
case ConversationDeltaSource.chat:
|
case ConversationDeltaSource.chat:
|
||||||
socketSubscription = service.addChatEventHandler(
|
_socketSubscription = service.addChatEventHandler(
|
||||||
conversationId: request.conversationId,
|
conversationId: request.conversationId,
|
||||||
sessionId: request.sessionId,
|
sessionId: request.sessionId,
|
||||||
requireFocus: request.requireFocus,
|
requireFocus: request.requireFocus,
|
||||||
handler: (event, ack) {
|
handler: (event, ack) {
|
||||||
if (!controller.isClosed) {
|
_controller?.add(
|
||||||
controller.add(
|
ConversationDelta.fromSocketEvent(
|
||||||
ConversationDelta.fromSocketEvent(
|
ConversationDeltaSource.chat,
|
||||||
ConversationDeltaSource.chat,
|
event,
|
||||||
event,
|
ack,
|
||||||
ack,
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case ConversationDeltaSource.channel:
|
case ConversationDeltaSource.channel:
|
||||||
socketSubscription = service.addChannelEventHandler(
|
_socketSubscription = service.addChannelEventHandler(
|
||||||
conversationId: request.conversationId,
|
conversationId: request.conversationId,
|
||||||
sessionId: request.sessionId,
|
sessionId: request.sessionId,
|
||||||
requireFocus: request.requireFocus,
|
requireFocus: request.requireFocus,
|
||||||
handler: (event, ack) {
|
handler: (event, ack) {
|
||||||
if (!controller.isClosed) {
|
_controller?.add(
|
||||||
controller.add(
|
ConversationDelta.fromSocketEvent(
|
||||||
ConversationDelta.fromSocketEvent(
|
ConversationDeltaSource.channel,
|
||||||
ConversationDeltaSource.channel,
|
event,
|
||||||
event,
|
ack,
|
||||||
ack,
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final initialService = ref
|
void _maybeTearDownSocket() {
|
||||||
.watch(socketServiceManagerProvider)
|
if (_controller?.hasListener == true) {
|
||||||
.maybeWhen(data: (service) => service, orElse: () => null);
|
return;
|
||||||
bindSocket(initialService);
|
}
|
||||||
|
_socketSubscription?.dispose();
|
||||||
|
_socketSubscription = null;
|
||||||
|
}
|
||||||
|
|
||||||
serviceSubscription = ref.listen<AsyncValue<SocketService?>>(
|
/// Provides direct access to the underlying stream.
|
||||||
socketServiceManagerProvider,
|
/// Note: This getter is necessary for compatibility with StreamProvider.
|
||||||
(_, next) => bindSocket(
|
/// While Riverpod 3 discourages public getters on Notifiers, this is a
|
||||||
next.maybeWhen(data: (service) => service, orElse: () => null),
|
/// pragmatic exception for stream delegation patterns.
|
||||||
),
|
// ignore: avoid_public_notifier_properties
|
||||||
);
|
Stream<ConversationDelta> get stream =>
|
||||||
|
_controller?.stream ?? const Stream<ConversationDelta>.empty();
|
||||||
ref.onDispose(() {
|
|
||||||
serviceSubscription?.close();
|
|
||||||
socketSubscription?.dispose();
|
|
||||||
controller.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
return controller.stream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final conversationDeltaEventsProvider =
|
||||||
|
StreamProvider.family<ConversationDelta, ConversationDeltaRequest>((
|
||||||
|
ref,
|
||||||
|
request,
|
||||||
|
) {
|
||||||
|
final notifier = ref.watch(
|
||||||
|
conversationDeltaStreamProvider(request).notifier,
|
||||||
|
);
|
||||||
|
return notifier.stream;
|
||||||
|
});
|
||||||
|
|
||||||
// Attachment upload queue provider
|
// Attachment upload queue provider
|
||||||
final attachmentUploadQueueProvider = Provider<AttachmentUploadQueue?>((ref) {
|
final attachmentUploadQueueProvider = Provider<AttachmentUploadQueue?>((ref) {
|
||||||
final api = ref.watch(apiServiceProvider);
|
final api = ref.watch(apiServiceProvider);
|
||||||
|
|||||||
@@ -1331,25 +1331,29 @@ Future<void> regenerateMessage(
|
|||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
final chatEventsStream = ref.read(
|
final chatEventsStream = ref
|
||||||
conversationDeltaStreamProvider(
|
.read(
|
||||||
ConversationDeltaRequest.chat(
|
conversationDeltaStreamProvider(
|
||||||
conversationId: activeConversation.id,
|
ConversationDeltaRequest.chat(
|
||||||
sessionId: effectiveSessionId,
|
conversationId: activeConversation.id,
|
||||||
requireFocus: false,
|
sessionId: effectiveSessionId,
|
||||||
),
|
requireFocus: false,
|
||||||
),
|
),
|
||||||
);
|
).notifier,
|
||||||
|
)
|
||||||
|
.stream;
|
||||||
|
|
||||||
final channelEventsStream = ref.read(
|
final channelEventsStream = ref
|
||||||
conversationDeltaStreamProvider(
|
.read(
|
||||||
ConversationDeltaRequest.channel(
|
conversationDeltaStreamProvider(
|
||||||
conversationId: activeConversation.id,
|
ConversationDeltaRequest.channel(
|
||||||
sessionId: effectiveSessionId,
|
conversationId: activeConversation.id,
|
||||||
requireFocus: false,
|
sessionId: effectiveSessionId,
|
||||||
),
|
requireFocus: false,
|
||||||
),
|
),
|
||||||
);
|
).notifier,
|
||||||
|
)
|
||||||
|
.stream;
|
||||||
|
|
||||||
final activeStream = attachUnifiedChunkedStreaming(
|
final activeStream = attachUnifiedChunkedStreaming(
|
||||||
stream: stream,
|
stream: stream,
|
||||||
@@ -1897,25 +1901,29 @@ Future<void> _sendMessageInternal(
|
|||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
final chatEventsStream = ref.read(
|
final chatEventsStream = ref
|
||||||
conversationDeltaStreamProvider(
|
.read(
|
||||||
ConversationDeltaRequest.chat(
|
conversationDeltaStreamProvider(
|
||||||
conversationId: activeConversation?.id,
|
ConversationDeltaRequest.chat(
|
||||||
sessionId: effectiveSessionId,
|
conversationId: activeConversation?.id,
|
||||||
requireFocus: false,
|
sessionId: effectiveSessionId,
|
||||||
),
|
requireFocus: false,
|
||||||
),
|
),
|
||||||
);
|
).notifier,
|
||||||
|
)
|
||||||
|
.stream;
|
||||||
|
|
||||||
final channelEventsStream = ref.read(
|
final channelEventsStream = ref
|
||||||
conversationDeltaStreamProvider(
|
.read(
|
||||||
ConversationDeltaRequest.channel(
|
conversationDeltaStreamProvider(
|
||||||
conversationId: activeConversation?.id,
|
ConversationDeltaRequest.channel(
|
||||||
sessionId: effectiveSessionId,
|
conversationId: activeConversation?.id,
|
||||||
requireFocus: false,
|
sessionId: effectiveSessionId,
|
||||||
),
|
requireFocus: false,
|
||||||
),
|
),
|
||||||
);
|
).notifier,
|
||||||
|
)
|
||||||
|
.stream;
|
||||||
|
|
||||||
final activeStream = attachUnifiedChunkedStreaming(
|
final activeStream = attachUnifiedChunkedStreaming(
|
||||||
stream: stream,
|
stream: stream,
|
||||||
|
|||||||
Submodule tmp/flutter_ai_repo deleted from 79187cf7e3
Reference in New Issue
Block a user