|
23 | 23 | "outputs": [], |
24 | 24 | "source": [ |
25 | 25 | "#| export\n", |
26 | | - "import inspect, json, importlib, linecache\n", |
| 26 | + "import json, importlib, linecache\n", |
27 | 27 | "from typing import Dict\n", |
28 | 28 | "from tempfile import TemporaryDirectory\n", |
29 | 29 | "from ipykernel_helper import *\n", |
|
33 | 33 | "from fastcore.meta import delegates\n", |
34 | 34 | "from ghapi.all import *\n", |
35 | 35 | "from fastlite import *\n", |
36 | | - "from fastcore.xtras import asdict" |
| 36 | + "from fastcore.xtras import asdict\n", |
| 37 | + "from inspect import currentframe,Parameter,signature" |
| 38 | + ] |
| 39 | + }, |
| 40 | + { |
| 41 | + "cell_type": "code", |
| 42 | + "execution_count": null, |
| 43 | + "metadata": {}, |
| 44 | + "outputs": [], |
| 45 | + "source": [ |
| 46 | + "from IPython.display import display,Markdown" |
37 | 47 | ] |
38 | 48 | }, |
39 | 49 | { |
|
100 | 110 | "#| export\n", |
101 | 111 | "def find_var(var:str):\n", |
102 | 112 | " \"Search for var in all frames of the call stack\"\n", |
103 | | - " frame = inspect.currentframe()\n", |
| 113 | + " frame = currentframe()\n", |
104 | 114 | " while frame:\n", |
105 | 115 | " dv = frame.f_globals.get(var, frame.f_locals.get(var, None))\n", |
106 | 116 | " if dv: return dv\n", |
|
456 | 466 | "name": "stdout", |
457 | 467 | "output_type": "stream", |
458 | 468 | "text": [ |
459 | | - "testfoo='testbar'\n" |
| 469 | + "__all__ = [\"hi\"]\n", |
| 470 | + "\n", |
| 471 | + "testfoo='testbar'\n", |
| 472 | + "\n", |
| 473 | + "def hi(\n", |
| 474 | + " who:str # who to say hi to\n", |
| 475 | + "):\n", |
| 476 | + " \"Say hi to `who`\"…\n" |
460 | 477 | ] |
461 | 478 | } |
462 | 479 | ], |
463 | 480 | "source": [ |
464 | 481 | "gfile = gist_file(gistid)\n", |
465 | | - "print(gfile.content)" |
| 482 | + "print(gfile.content[:100]+\"…\")" |
466 | 483 | ] |
467 | 484 | }, |
468 | 485 | { |
|
488 | 505 | " return module" |
489 | 506 | ] |
490 | 507 | }, |
| 508 | + { |
| 509 | + "cell_type": "code", |
| 510 | + "execution_count": null, |
| 511 | + "metadata": {}, |
| 512 | + "outputs": [], |
| 513 | + "source": [ |
| 514 | + "#| export\n", |
| 515 | + "empty = Parameter.empty\n", |
| 516 | + "\n", |
| 517 | + "def is_usable_tool(func:callable):\n", |
| 518 | + " \"True if the function has a docstring and all parameters have types, meaning that it can be used as an LLM tool.\" \n", |
| 519 | + " if not func.__doc__ or not callable(func): return False\n", |
| 520 | + " return all(p.annotation != empty for p in signature(func).parameters.values())" |
| 521 | + ] |
| 522 | + }, |
| 523 | + { |
| 524 | + "cell_type": "code", |
| 525 | + "execution_count": null, |
| 526 | + "metadata": {}, |
| 527 | + "outputs": [], |
| 528 | + "source": [ |
| 529 | + "def hi(who:str):\n", |
| 530 | + " \"Say hi to `who`\"\n", |
| 531 | + " return f\"Hello {who}\"\n", |
| 532 | + "\n", |
| 533 | + "def hi2(who):\n", |
| 534 | + " \"Say hi to `who`\"\n", |
| 535 | + " return f\"Hello {who}\"\n", |
| 536 | + "\n", |
| 537 | + "def hi3(who:str):\n", |
| 538 | + " return f\"Hello {who}\"\n", |
| 539 | + "\n", |
| 540 | + "bye = \"bye\"" |
| 541 | + ] |
| 542 | + }, |
| 543 | + { |
| 544 | + "cell_type": "code", |
| 545 | + "execution_count": null, |
| 546 | + "metadata": {}, |
| 547 | + "outputs": [], |
| 548 | + "source": [ |
| 549 | + "assert is_usable_tool(hi)\n", |
| 550 | + "assert not is_usable_tool(hi2)\n", |
| 551 | + "assert not is_usable_tool(hi3)\n", |
| 552 | + "assert not is_usable_tool(bye)" |
| 553 | + ] |
| 554 | + }, |
| 555 | + { |
| 556 | + "cell_type": "code", |
| 557 | + "execution_count": null, |
| 558 | + "metadata": {}, |
| 559 | + "outputs": [], |
| 560 | + "source": [ |
| 561 | + "#| export\n", |
| 562 | + "def mk_toollist(syms):\n", |
| 563 | + " return \"\\n\".join(f\"- &`{sym.__name__}`: {sym.__doc__}\" for sym in syms if is_usable_tool(sym))" |
| 564 | + ] |
| 565 | + }, |
| 566 | + { |
| 567 | + "cell_type": "code", |
| 568 | + "execution_count": null, |
| 569 | + "metadata": {}, |
| 570 | + "outputs": [ |
| 571 | + { |
| 572 | + "data": { |
| 573 | + "text/markdown": [ |
| 574 | + "- &`hi`: Say hi to `who`" |
| 575 | + ], |
| 576 | + "text/plain": [ |
| 577 | + "<IPython.core.display.Markdown object>" |
| 578 | + ] |
| 579 | + }, |
| 580 | + "execution_count": null, |
| 581 | + "metadata": {}, |
| 582 | + "output_type": "execute_result" |
| 583 | + } |
| 584 | + ], |
| 585 | + "source": [ |
| 586 | + "Markdown(mk_toollist([hi]))" |
| 587 | + ] |
| 588 | + }, |
491 | 589 | { |
492 | 590 | "cell_type": "code", |
493 | 591 | "execution_count": null, |
|
498 | 596 | "def import_gist(\n", |
499 | 597 | " gist_id:str, # user/id or just id of gist to import as a module\n", |
500 | 598 | " mod_name:str=None, # module name to create (taken from gist filename if not passed)\n", |
501 | | - " add_global:bool=True # add module to caller's globals?\n", |
| 599 | + " add_global:bool=True, # add module to caller's globals?\n", |
| 600 | + " import_wildcard:bool=False, # import all exported symbols to caller's globals\n", |
| 601 | + " create_msg:bool=False # Add a message that lists usable tools\n", |
502 | 602 | "):\n", |
503 | 603 | " \"Import gist directly from string without saving to disk\"\n", |
504 | 604 | " fil = gist_file(gist_id)\n", |
505 | 605 | " mod_name = mod_name or Path(fil['filename']).stem\n", |
506 | 606 | " module = import_string(fil['content'], mod_name)\n", |
507 | | - " if add_global: inspect.currentframe().f_back.f_globals[mod_name] = module\n", |
| 607 | + " glbs = currentframe().f_back.f_globals\n", |
| 608 | + " if add_global: glbs[mod_name] = module\n", |
| 609 | + " syms = getattr(module, '__all__', None)\n", |
| 610 | + " if syms is None: syms = [o for o in dir(module) if not o.startswith('_')]\n", |
| 611 | + " syms = [getattr(module, nm) for nm in syms]\n", |
| 612 | + " if import_wildcard:\n", |
| 613 | + " for sym in syms: glbs[sym.__name__] = sym\n", |
| 614 | + " if create_msg: add_msg(f\"Tools added to dialog:\\n\\n{mk_toollist(syms)}\")\n", |
508 | 615 | " return module" |
509 | 616 | ] |
510 | 617 | }, |
|
529 | 636 | "importtest.testfoo" |
530 | 637 | ] |
531 | 638 | }, |
| 639 | + { |
| 640 | + "cell_type": "code", |
| 641 | + "execution_count": null, |
| 642 | + "metadata": {}, |
| 643 | + "outputs": [ |
| 644 | + { |
| 645 | + "data": { |
| 646 | + "text/plain": [ |
| 647 | + "'testbar'" |
| 648 | + ] |
| 649 | + }, |
| 650 | + "execution_count": null, |
| 651 | + "metadata": {}, |
| 652 | + "output_type": "execute_result" |
| 653 | + } |
| 654 | + ], |
| 655 | + "source": [ |
| 656 | + "import_gist(gistid, import_wildcard=True)\n", |
| 657 | + "importtest.testfoo" |
| 658 | + ] |
| 659 | + }, |
| 660 | + { |
| 661 | + "cell_type": "code", |
| 662 | + "execution_count": null, |
| 663 | + "metadata": {}, |
| 664 | + "outputs": [ |
| 665 | + { |
| 666 | + "data": { |
| 667 | + "text/plain": [ |
| 668 | + "'Hello Sarah'" |
| 669 | + ] |
| 670 | + }, |
| 671 | + "execution_count": null, |
| 672 | + "metadata": {}, |
| 673 | + "output_type": "execute_result" |
| 674 | + } |
| 675 | + ], |
| 676 | + "source": [ |
| 677 | + "hi(\"Sarah\")" |
| 678 | + ] |
| 679 | + }, |
| 680 | + { |
| 681 | + "cell_type": "code", |
| 682 | + "execution_count": null, |
| 683 | + "metadata": {}, |
| 684 | + "outputs": [ |
| 685 | + { |
| 686 | + "data": { |
| 687 | + "text/plain": [ |
| 688 | + "['hi']" |
| 689 | + ] |
| 690 | + }, |
| 691 | + "execution_count": null, |
| 692 | + "metadata": {}, |
| 693 | + "output_type": "execute_result" |
| 694 | + } |
| 695 | + ], |
| 696 | + "source": [ |
| 697 | + "importtest.__all__" |
| 698 | + ] |
| 699 | + }, |
532 | 700 | { |
533 | 701 | "cell_type": "markdown", |
534 | 702 | "metadata": {}, |
|
0 commit comments