Spaces:
Sleeping
Sleeping
Update src/App.tsx
Browse files- 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 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|