Add web research and source file reading

This commit is contained in:
Hamza Ayed
2026-10-01 14:06:36 +03:00
parent 2d3778a92e
commit dc4d5bad0f
9 changed files with 310 additions and 23 deletions
@@ -88,6 +88,19 @@ class ChatCubit extends Cubit<ChatState> {
emit(
state.copyWith(
isWorkspaceMode: !state.isWorkspaceMode,
isWebSearchMode: false,
clearError: true,
),
);
}
}
void toggleWebSearchMode() {
if (!state.isSending) {
emit(
state.copyWith(
isWebSearchMode: !state.isWebSearchMode,
isWorkspaceMode: false,
clearError: true,
),
);
@@ -254,11 +267,11 @@ class ChatCubit extends Cubit<ChatState> {
),
);
_startElapsedTimer(generation);
if (state.isWorkspaceMode) {
answer = await _api.askWorkspaceAgent(
prompt,
model: state.selectedModel,
);
if (state.isWorkspaceMode || state.isWebSearchMode) {
answer =
state.isWorkspaceMode
? await _api.askWorkspaceAgent(prompt, model: state.selectedModel)
: await _api.searchWeb(prompt, model: state.selectedModel);
if (isClosed || generation != _requestGeneration) return;
if (answer.trim().isEmpty) {
throw Exception('لم يصل نص في إجابة الوكيل.');
@@ -81,6 +81,7 @@ class ChatState {
this.isLoadingHistory = true,
this.isSending = false,
this.isWorkspaceMode = false,
this.isWebSearchMode = false,
this.error,
this.modelName = 'جارٍ اكتشاف النموذج…',
this.modelStatus = ModelConnectionStatus.checking,
@@ -98,6 +99,7 @@ class ChatState {
final bool isLoadingHistory;
final bool isSending;
final bool isWorkspaceMode;
final bool isWebSearchMode;
final String? error;
final String modelName;
final ModelConnectionStatus modelStatus;
@@ -116,6 +118,7 @@ class ChatState {
bool? isLoadingHistory,
bool? isSending,
bool? isWorkspaceMode,
bool? isWebSearchMode,
String? error,
bool clearError = false,
String? modelName,
@@ -138,6 +141,7 @@ class ChatState {
isLoadingHistory: isLoadingHistory ?? this.isLoadingHistory,
isSending: isSending ?? this.isSending,
isWorkspaceMode: isWorkspaceMode ?? this.isWorkspaceMode,
isWebSearchMode: isWebSearchMode ?? this.isWebSearchMode,
error: clearError ? null : (error ?? this.error),
modelName: modelName ?? this.modelName,
modelStatus: modelStatus ?? this.modelStatus,
@@ -554,6 +554,18 @@ class _ChatPageState extends State<ChatPage> {
: Icons.folder_outlined,
),
),
IconButton(
onPressed: () => context.read<ChatCubit>().toggleWebSearchMode(),
tooltip:
context.watch<ChatCubit>().state.isWebSearchMode
? 'إيقاف البحث العميق على الإنترنت'
: 'بحث عميق على الإنترنت من عدة مصادر',
color:
context.watch<ChatCubit>().state.isWebSearchMode
? _green
: _ink,
icon: const Icon(Icons.travel_explore_rounded),
),
if (context.watch<ChatCubit>().state.availableModels.isNotEmpty)
ConstrainedBox(
constraints: BoxConstraints(maxWidth: compact ? 100 : 190),
@@ -690,7 +702,9 @@ class _ChatPageState extends State<ChatPage> {
const SizedBox(height: 8),
Text(
context.watch<ChatCubit>().state.isWorkspaceMode
? 'وضع الوكيل يبحث في ملفات المشروع للقراءة فقط.'
? 'وضع الملفات: اسأل عن ملفات الكود في مساحة العمل للقراءة فقط.'
: context.watch<ChatCubit>().state.isWebSearchMode
? 'بحث عميق: يجلب مصادر ويب متعددة ويلخصها مع الروابط.'
: 'اكتب سؤالك، وسأرسله إلى النموذج المحلي على جهازك.',
style: const TextStyle(color: Color(0xFF718078), fontSize: 14),
),
@@ -947,7 +961,9 @@ class _ChatPageState extends State<ChatPage> {
decoration: InputDecoration(
hintText:
chat.isWorkspaceMode
? 'اسأل عن ملفات مساحة العمل…'
? 'اسأل عن ملف كود أو عن مساحة العمل…'
: chat.isWebSearchMode
? 'ما الموضوع الذي تريد البحث عنه على الإنترنت؟'
: 'اكتب رسالتك هنا…',
hintStyle: TextStyle(color: Color(0xFF9BA59E)),
border: InputBorder.none,