inspecttools

LLM tools for inspecting the symbol table and importing modules

This module provides LLM tools to dynamically inspect source code, types, and module capabilities. Functions take string arguments (dotted symbol paths) rather than Python objects because LLM tool interfaces can only pass serializable values—not live Python references.

from IPython.display import display,Markdown
import textwrap

Helpers


source

importmodule


def importmodule(
    mod:str, # The module to import (e.g. 'torch.nn.functional')
    caller_symbol:str='__msg_id', # The name of the special variable to find the correct caller namespace
):

Import a module into the caller’s global namespace so it’s available for symsrc, symval, symdir, etc. Use this before inspecting or using symbols from modules not yet imported.

importmodule lets the LLM dynamically import modules by name. Here we import fastcore.utils and verify it’s available.

importmodule('fastcore.utils')
fastcore.__version__
'1.12.5'

source

resolve


def resolve(
    sym:str, # Dotted symbol path, with optional [n] indexing, e.g. "module.attr.subattr[1]" or "_last" for previous result
):

Resolve a dotted symbol string to its Python object, with optional [n] indexing. Sets global _last to the resolved object for chaining. Pass "_last" to reference the result of the previous tool call.

Examples:

  • resolve("sympy.sets.sets.Interval") -> <class 'sympy.sets.sets.Interval'>
  • resolve("mylist[2]") -> third element of mylist

source

SymbolNotFound


def SymbolNotFound(
    args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):

Common base class for all non-exit exceptions.

resolve navigates dotted paths like "a.argfirst" to reach the actual Python object.

a = fastcore.utils.L(1)
resolve('a.argfirst')
<bound method L.argfirst of [1]>

It also sets _last for chaining. Since it’s used internally by all get* tools in this module, the tools all set _last too.

_last
<bound method L.argfirst of [1]>

It works on both objects and classes:

resolve('fastcore.utils.L.argfirst')
<function fastcore.foundation.L.argfirst(self: fastcore.foundation.L, f, negate=False)>

Symbol info


source

symsrc


def symsrc(
    sym:str, # Dotted symbol path (e.g `Interval` or `sympy.sets.sets.Interval`) or "_last" for previous result
):

Get the source code for a symbol.

Examples:

  • symsrc("Interval") -> source code of Interval class if it’s already imported
  • symsrc("sympy.sets.sets.Interval") -> source code of Interval class
  • symsrc("_last") -> source of object from previous tool call
  • For dispatchers or registries of callables: symnth("module.dispatcher.funcs", n) then symsrc("_last")

symsrc retrieves the source code of any symbol by path—essential for letting the LLM understand how functions work.

print(symsrc('a.argfirst'))
File: /Users/jhoward/aai-ws/fastcore/fastcore/foundation.py

@patch
@curryable
def argfirst(self:L, f, negate=False):
    "Return index of first matching item"
    if negate: f = not_(f)
    return first(i for i,o in self.enumerate() if f(o))
class B:
    def a(): ...
b = B()
print(symsrc('b'))
File: /var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipykernel_33003/2711726673.py

class B:
    def a(): ...
def f():
    "testing"
    return 1
print(symsrc('f'))
File: /var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipykernel_33003/242320393.py

def f():
    "testing"
    return 1
from toolslm import xml
print(symsrc('xml')[:200])
File: /Users/jhoward/aai-ws/toolslm/toolslm/xml.py

# AUTOGENERATED! DO NOT EDIT! File to edit: ../00_xml.ipynb.

# %% auto #0
__all__ = ['doctype', 'json_to_xml', 'get_mime_text', 'cell2out', 'cell2x

source

symtype


def symtype(
    syms:str, # Comma separated str list of dotted symbol paths (e.g `'Interval,a'` or `'sympy.sets.sets.Interval'`); "_last" for prev result
):

Get the type of a symbol and set _last.

Examples:

  • symtype("sympy.sets.sets.Interval") -> <class 'type'>
  • symtype("doesnotexist") -> 'SymbolNotFound
  • symtype("_last") -> type of previous result

symtype returns the type of a symbol—useful for the LLM to understand what kind of object it’s dealing with.

symtype('a.argfirst')
[method]
symtype('fffaa,b')
["SymbolNotFound(Symbol 'fffaa' not found. Consider using `importmodule` first.)",
 __main__.B]

source

symval


def symval(
    syms:str, # Comma separated str list of dotted symbol paths (e.g `Interval` or `sympy.sets.sets.Interval`); "_last" for prev result
):

List of repr of symbols’ values.

Examples:

  • symval("sympy.sets.sets.Interval") -> [<class 'sympy.sets.sets.Interval'>]
  • symval("some_dict.keys") -> [dict_keys([...])]
  • symval("a,notexist") -> ['foo','SymbolNotFound']

symval returns the repr() of a symbol’s value—handy for inspecting data without needing to execute arbitrary code.

a
[1]
symval('a,foofoo')
['[1]',
 "SymbolNotFound(Symbol 'foofoo' not found. Consider using `importmodule` first.)"]

source

symtype_val


def symtype_val(
    syms:str, # Comma separated str list of dotted symbol paths (e.g `Interval` or `sympy.sets.sets.Interval`); "_last" for prev result
):

List of 2-ple of (type,repr) of symbols’ values.

Examples:

  • symtype_val("a,c,notexist") -> [(<class 'str'>,'foo'),(<class 'int'>,1), 'SymbolNotFound']
symtype_val('a,b,foofoo')
[(fastcore.foundation.L, '[1]'),
 (__main__.B, '<__main__.B object>'),
 'SymbolNotFound']

source

symdir


def symdir(
    sym:str, # Dotted symbol path (e.g `Interval` or `sympy.sets.sets.Interval`) or "_last" for previous result
    exclude_private:bool=False, # Filter out attrs starting with "_"
):

Get dir() listing of a symbol’s attributes and set _last. E.g: symdir("sympy.Interval") -> ['__add__', '__and__', ...]

symdir lists all attributes of an object (i.e it calls dir(). Here we filter out private names to see the public API of an L list.

' '.join(symdir('a', exclude_private=True))
'accumulate append argfirst argwhere attrgot batched clear combinations compress concat copy copy count cycle dropwhile enumerate extend filter flatmap flatten groupby index insert itemgot items map map_dict map_first map_zip map_zipwith pairwise partition permutations pop product range reduce remove renumerate reverse rstarargfirst rstarargwhere rstardropwhile rstarfilter rstarmap rstarpartition rstarreduce rstarsorted rstartakewhile setattrs shuffle sort sorted split splitlines starargfirst starargwhere stardropwhile starfilter starmap starpartition starreduce starsorted startakewhile sum takewhile unique val2idx zip zipwith'

source

symnth


def symnth(
    sym:str, # Dotted symbol path to a dict or object with .values()
    n:int, # Index into the values (0-based)
):

Get the nth value from a dict (or any object with .values()). Sets _last so you can chain with symsrc("_last") etc.

Examples:

  • symnth("dispatcher.funcs", 12) -> 13th registered function
  • symnth("dispatcher.funcs", 0); symsrc("_last") -> source of first handler

symnth extracts the nth value from a dict (or anything with .values()).

handlers = dict(int=lambda x: x*2, str=lambda x: x.upper(), list=lambda x: len(x))
symnth('handlers', 0)
<function __main__.<lambda>(x)>

Combined with _last, this lets the LLM drill into registries of handlers/dispatchers and then inspect their source.

symsrc('_last')
'File: /var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipykernel_33003/340145363.py\n\nhandlers = dict(int=lambda x: x*2, str=lambda x: x.upper(), list=lambda x: len(x))\n'

source

symlen


def symlen(
    sym:str, # Dotted symbol path or "_last" for previous result
):

Returns the length of the given symbol


source

symslice


def symslice(
    sym:str, # Dotted symbol path or "_last" for previous result
    start:int, # Starting index for slice
    end:int, # Ending index for slice
):

Returns the contents of the symbol from the given start to the end.

a = ['a', 'b', 'c', 'd']
symslice('a', 1, 3)
['b', 'c']

On failure we get a str error:

symslice('resolve', 0, 1)
"Error: 'function' object is not subscriptable"

source

symsearch


def symsearch(
    sym:str, # Dotted symbol path or "_last" for previous result
    term:str, # Search term (exact string or regex pattern)
    regex:bool=True, # If True, regex search; if False, exact match
    flags:int=0, # Regex flags (e.g., re.IGNORECASE)
):

Search contents of symbol, which is assumed to be str for regex, or iterable for non-regex. Regex mode returns (match, start, end) tuples; otherwise returns (item, index) tuples

symsearch('a', 'c', regex=False), symsearch('a', 'z', regex=False)
("[('c', 2)]", '[]')
text = "The quick brown fox jumps over 3 lazy dogs and 12 cats"
symsearch('text', r'\d+', regex=True)
"[('3', 31, 32), ('12', 47, 49)]"
symsearch('text', r'\b[aeiou]\w*', regex=True, flags=re.IGNORECASE)
"[('over', 26, 30), ('and', 43, 46)]"

source

symset


def symset(
    val:str, # Value to assign to _ai_sym
):

*Set _ai_sym to the given value*

symset('Otters are awesome!'); _ai_sym
'Otters are awesome!'

Symbol context


source

symfiles_folder


def symfiles_folder(
    sym:str, # Dotted symbol path or "_last" for previous result
    types:str | list='py', # List or comma-separated str of ext types from: py, js, java, c, cpp, rb, r, ex, sh, web, doc, cfg
    skip_file_re:str='^_mod', # Skip files matching regex
    prefix:bool=False, # Include Anthropic's suggested prose intro?
    out:bool=True, # Include notebook cell outputs?
    include_base:bool=True, # Include full path in src?
    title:str=None, # Optional title attr for Documents element
    max_size:int=100000, # Skip files larger than this (bytes)
    max_total:int=10000000, # Max total output size in bytes
    readme_first:bool=False, # Prioritize README files at start of context?
    files_only:bool=False, # Return dict of {filename: size} instead of context?
    sigs_only:bool=False, # Return signatures instead of full text? (where supported by `codesigs` lib)
    ids:bool=True, # Include cell ids in notebooks?
    recursive:bool=True, # search subfolders
    symlinks:bool=True, # follow symlinks?
    file_glob:str=None, # Only include files matching glob
    file_re:str=None, # Only include files matching regex
    folder_re:str=None, # Only enter folders matching regex
    skip_file_glob:str=None, # Skip files matching glob
    skip_folder_re:str=None, # Skip folders matching regex,
    ret_folders:bool=False, # return folders, not just files
    sort:bool=True, # sort files by name within each folder
    exts:str | list=None, # list or comma-separated str of exts to include
):

Return XML context of files in the folder containing sym’s definition

# print(symfiles_folder('xml'))

source

symfiles_package


def symfiles_package(
    sym:str, # Dotted symbol path or "_last" for previous result
    types:str | list='py', # List or comma-separated str of ext types from: py, js, java, c, cpp, rb, r, ex, sh, web, doc, cfg
    skip_file_re:str='^_mod', # Skip files matching regex
    skip_folder_re:str='^(\\.|__)', # Skip folders matching regex
    prefix:bool=False, # Include Anthropic's suggested prose intro?
    out:bool=True, # Include notebook cell outputs?
    include_base:bool=True, # Include full path in src?
    title:str=None, # Optional title attr for Documents element
    max_size:int=100000, # Skip files larger than this (bytes)
    max_total:int=10000000, # Max total output size in bytes
    readme_first:bool=False, # Prioritize README files at start of context?
    files_only:bool=False, # Return dict of {filename: size} instead of context?
    sigs_only:bool=False, # Return signatures instead of full text? (where supported by `codesigs` lib)
    ids:bool=True, # Include cell ids in notebooks?
    recursive:bool=True, # search subfolders
    symlinks:bool=True, # follow symlinks?
    file_glob:str=None, # Only include files matching glob
    file_re:str=None, # Only include files matching regex
    folder_re:str=None, # Only enter folders matching regex
    skip_file_glob:str=None, # Skip files matching glob
    ret_folders:bool=False, # return folders, not just files
    sort:bool=True, # sort files by name within each folder
    exts:str | list=None, # list or comma-separated str of exts to include
):

Return XML context of all files in sym’s top-level package

# print(symfiles_package('xml'))