drdata commited on
Commit
43df02e
·
verified ·
1 Parent(s): ac80eab

Update src/App.tsx

Browse files
Files changed (1) hide show
  1. src/App.tsx +306 -1
src/App.tsx CHANGED
@@ -341,4 +341,309 @@ const App: React.FC = () => {
341
  finalArgs.push(positionalArgs[i]);
342
  } else if (Object.prototype.hasOwnProperty.call(keywordArgs, paramName)) {
343
  finalArgs.push(keywordArgs[paramName]);
344
- } els
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  finalArgs.push(positionalArgs[i]);
342
  } else if (Object.prototype.hasOwnProperty.call(keywordArgs, paramName)) {
343
  finalArgs.push(keywordArgs[paramName]);
344
+ } else if (
345
+ Object.prototype.hasOwnProperty.call(
346
+ schema.parameters.properties[paramName],
347
+ "default"
348
+ )
349
+ ) {
350
+ finalArgs.push(schema.parameters.properties[paramName].default);
351
+ } else if (!requiredParams.includes(paramName)) {
352
+ finalArgs.push(undefined);
353
+ } else {
354
+ throw new Error(`Missing required argument: ${paramName}`);
355
+ }
356
+ }
357
+
358
+ const bodyMatch = functionCode.match(/function[^{]+{([\s\S]*)}/);
359
+ if (!bodyMatch) {
360
+ throw new Error(
361
+ "Could not parse function body. Ensure it's a standard `function` declaration."
362
+ );
363
+ }
364
+ const body = bodyMatch[1];
365
+ const AsyncFunction = Object.getPrototypeOf(
366
+ async function () {}
367
+ ).constructor;
368
+ const func = new AsyncFunction(...paramNames, body);
369
+ const result = await func(...finalArgs);
370
+ console.log('✅ Local tool result:', result);
371
+ return JSON.stringify(result);
372
+ };
373
+
374
+ const executeToolCalls = async (
375
+ toolCallContent: string
376
+ ): Promise<RenderInfo[]> => {
377
+ console.log('🔧 Executing tool calls from content:', toolCallContent);
378
+
379
+ const toolCalls = extractPythonicCalls(toolCallContent);
380
+
381
+ if (toolCalls.length === 0) {
382
+ console.warn('⚠️ No valid tool calls found');
383
+ return [{ call: "", error: "No valid tool calls found." }];
384
+ }
385
+
386
+ console.log('🔧 Found tool calls:', toolCalls);
387
+
388
+ const results: RenderInfo[] = [];
389
+ for (const call of toolCalls) {
390
+ try {
391
+ const result = await executeToolCall(call);
392
+ const parsedCall = parsePythonicCalls(call);
393
+ const toolUsed = parsedCall
394
+ ? tools.find((t) => t.name === parsedCall.name && t.enabled)
395
+ : null;
396
+ const { rendererCode } = toolUsed
397
+ ? extractFunctionAndRenderer(toolUsed.code)
398
+ : { rendererCode: undefined };
399
+
400
+ let parsedResult;
401
+ try {
402
+ parsedResult = JSON.parse(result);
403
+ } catch {
404
+ parsedResult = result;
405
+ }
406
+
407
+ let namedParams: Record<string, unknown> = Object.create(null);
408
+ if (parsedCall && toolUsed) {
409
+ const schema = generateSchemaFromCode(
410
+ extractFunctionAndRenderer(toolUsed.code).functionCode
411
+ );
412
+ const paramNames = Object.keys(schema.parameters.properties);
413
+ namedParams = mapArgsToNamedParams(
414
+ paramNames,
415
+ parsedCall.positionalArgs,
416
+ parsedCall.keywordArgs
417
+ );
418
+ }
419
+
420
+ results.push({
421
+ call,
422
+ result: parsedResult,
423
+ renderer: rendererCode,
424
+ input: namedParams,
425
+ });
426
+ } catch (error) {
427
+ const errorMessage = getErrorMessage(error);
428
+ console.error('❌ Tool execution error:', errorMessage);
429
+ results.push({ call, error: errorMessage });
430
+ }
431
+ }
432
+ return results;
433
+ };
434
+
435
+ const handleSendMessage = async (): Promise<void> => {
436
+ if (!input.trim() || !isReady) {
437
+ console.warn('⚠️ Cannot send message:', { inputEmpty: !input.trim(), isReady });
438
+ return;
439
+ }
440
+
441
+ console.log('🔵 Starting message send...', { input, isReady });
442
+
443
+ const userMessage: Message = { role: "user", content: input };
444
+ const currentMessages: Message[] = [...messages, userMessage];
445
+ setMessages(currentMessages);
446
+ setInput("");
447
+ setIsGenerating(true);
448
+
449
+ try {
450
+ const toolSchemas = tools
451
+ .filter((tool) => tool.enabled)
452
+ .map((tool) => generateSchemaFromCode(tool.code));
453
+
454
+ console.log('🟡 Enabled tools:', {
455
+ count: toolSchemas.length,
456
+ tools: toolSchemas.map(s => s.name)
457
+ });
458
+
459
+ let loopCount = 0;
460
+ const MAX_LOOPS = 10; // Prevent infinite loops
461
+
462
+ while (loopCount < MAX_LOOPS) {
463
+ loopCount++;
464
+ console.log(`🔄 Generation loop iteration ${loopCount}`);
465
+
466
+ const messagesForGeneration = [
467
+ { role: "system" as const, content: systemPrompt },
468
+ ...currentMessages,
469
+ ];
470
+
471
+ console.log('🟡 Calling generateResponse...', {
472
+ messageCount: messagesForGeneration.length,
473
+ toolSchemaCount: toolSchemas.length
474
+ });
475
+
476
+ setMessages([...currentMessages, { role: "assistant", content: "" }]);
477
+
478
+ let accumulatedContent = "";
479
+ let tokenCount = 0;
480
+
481
+ const response = await generateResponse(
482
+ messagesForGeneration,
483
+ toolSchemas,
484
+ (token: string) => {
485
+ tokenCount++;
486
+ accumulatedContent += token;
487
+ if (tokenCount % 10 === 0) {
488
+ console.log(`📝 Streaming... (${tokenCount} tokens)`);
489
+ }
490
+ setMessages((current) => {
491
+ const updated = [...current];
492
+ updated[updated.length - 1] = {
493
+ role: "assistant",
494
+ content: accumulatedContent,
495
+ };
496
+ return updated;
497
+ });
498
+ }
499
+ );
500
+
501
+ console.log('🟢 Response received:', {
502
+ length: response.length,
503
+ preview: response.substring(0, 100),
504
+ totalTokens: tokenCount
505
+ });
506
+
507
+ currentMessages.push({ role: "assistant", content: response });
508
+ const toolCallContent = extractToolCallContent(response);
509
+
510
+ if (toolCallContent) {
511
+ console.log('🔧 Tool call detected in response');
512
+ const toolResults = await executeToolCalls(toolCallContent);
513
+ console.log('🔧 Tool execution complete:', {
514
+ resultCount: toolResults.length,
515
+ hasErrors: toolResults.some(r => r.error)
516
+ });
517
+
518
+ const toolMessage: ToolMessage = {
519
+ role: "tool",
520
+ content: JSON.stringify(toolResults.map((r) => r.result ?? null)),
521
+ renderInfo: toolResults,
522
+ };
523
+ currentMessages.push(toolMessage);
524
+ setMessages([...currentMessages]);
525
+
526
+ console.log('🔄 Continuing generation loop with tool results');
527
+ continue;
528
+ } else {
529
+ console.log('✅ No tool calls detected, finishing generation');
530
+ setMessages(currentMessages);
531
+ break;
532
+ }
533
+ }
534
+
535
+ if (loopCount >= MAX_LOOPS) {
536
+ console.warn('⚠️ Maximum generation loops reached');
537
+ throw new Error('Maximum generation loops reached. The model may be stuck in a tool-calling loop.');
538
+ }
539
+
540
+ console.log('🏁 Generation complete successfully');
541
+ } catch (error) {
542
+ console.error('🔴 Error in handleSendMessage:', error);
543
+ const errorMessage = getErrorMessage(error);
544
+ setMessages([
545
+ ...currentMessages,
546
+ {
547
+ role: "assistant",
548
+ content: `Error generating response: ${errorMessage}`,
549
+ },
550
+ ]);
551
+ } finally {
552
+ setIsGenerating(false);
553
+ setTimeout(() => inputRef.current?.focus(), 0);
554
+ }
555
+ };
556
+
557
+ const loadSystemPrompt = useCallback(async (): Promise<void> => {
558
+ try {
559
+ const db = await getDB();
560
+ const stored = await db.get(SETTINGS_STORE_NAME, "systemPrompt");
561
+ if (stored && stored.value) setSystemPrompt(stored.value);
562
+ } catch (error) {
563
+ console.error("Failed to load system prompt:", error);
564
+ }
565
+ }, []);
566
+
567
+ const saveSystemPrompt = useCallback(
568
+ async (prompt: string): Promise<void> => {
569
+ try {
570
+ const db = await getDB();
571
+ await db.put(SETTINGS_STORE_NAME, {
572
+ key: "systemPrompt",
573
+ value: prompt,
574
+ });
575
+ } catch (error) {
576
+ console.error("Failed to save system prompt:", error);
577
+ }
578
+ },
579
+ []
580
+ );
581
+
582
+ const loadSelectedModel = useCallback(async (): Promise<void> => {
583
+ try {
584
+ await loadModel();
585
+ } catch (error) {
586
+ console.error("Failed to load model:", error);
587
+ }
588
+ }, [loadModel]);
589
+
590
+ const loadSelectedModelId = useCallback(async (): Promise<void> => {
591
+ try {
592
+ const db = await getDB();
593
+ const stored = await db.get(SETTINGS_STORE_NAME, "selectedModelId");
594
+ if (stored && stored.value) {
595
+ setSelectedModelId(stored.value);
596
+ }
597
+ } catch (error) {
598
+ console.error("Failed to load selected model ID:", error);
599
+ }
600
+ }, []);
601
+
602
+ useEffect(() => {
603
+ loadSystemPrompt();
604
+ }, [loadSystemPrompt]);
605
+
606
+ const handleOpenSystemPromptModal = (): void => {
607
+ setTempSystemPrompt(systemPrompt);
608
+ setIsSystemPromptModalOpen(true);
609
+ };
610
+
611
+ const handleSaveSystemPrompt = (): void => {
612
+ setSystemPrompt(tempSystemPrompt);
613
+ saveSystemPrompt(tempSystemPrompt);
614
+ setIsSystemPromptModalOpen(false);
615
+ };
616
+
617
+ const handleCancelSystemPrompt = (): void => {
618
+ setTempSystemPrompt("");
619
+ setIsSystemPromptModalOpen(false);
620
+ };
621
+
622
+ const handleResetSystemPrompt = (): void => {
623
+ setTempSystemPrompt(DEFAULT_SYSTEM_PROMPT);
624
+ };
625
+
626
+ const saveSelectedModel = useCallback(
627
+ async (modelId: string): Promise<void> => {
628
+ try {
629
+ const db = await getDB();
630
+ await db.put(SETTINGS_STORE_NAME, {
631
+ key: "selectedModelId",
632
+ value: modelId,
633
+ });
634
+ } catch (error) {
635
+ console.error("Failed to save selected model ID:", error);
636
+ }
637
+ },
638
+ []
639
+ );
640
+
641
+ useEffect(() => {
642
+ loadSystemPrompt();
643
+ loadSelectedModelId();
644
+ }, [loadSystemPrompt, loadSelectedModelId]);
645
+
646
+ const handleModelSelect = async (modelId: string) => {
647
+ setSelectedModelId(modelId);
648
+ setIsModelDropdownOpen(false);
649
+ a