toolslm 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
toolslm/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.0.2"
1
+ __version__ = "0.0.4"
toolslm/_modidx.py CHANGED
@@ -5,9 +5,12 @@ d = { 'settings': { 'branch': 'main',
5
5
  'doc_host': 'https://AnswerDotAI.github.io',
6
6
  'git_url': 'https://github.com/AnswerDotAI/toolslm',
7
7
  'lib_path': 'toolslm'},
8
- 'syms': { 'toolslm.lmcode': { 'toolslm.lmcode._copy_loc': ('lmcode.html#_copy_loc', 'toolslm/lmcode.py'),
9
- 'toolslm.lmcode._run': ('lmcode.html#_run', 'toolslm/lmcode.py'),
10
- 'toolslm.lmcode.python': ('lmcode.html#python', 'toolslm/lmcode.py')},
8
+ 'syms': { 'toolslm.funccall': { 'toolslm.funccall._copy_loc': ('funccall.html#_copy_loc', 'toolslm/funccall.py'),
9
+ 'toolslm.funccall._param': ('funccall.html#_param', 'toolslm/funccall.py'),
10
+ 'toolslm.funccall._run': ('funccall.html#_run', 'toolslm/funccall.py'),
11
+ 'toolslm.funccall._types': ('funccall.html#_types', 'toolslm/funccall.py'),
12
+ 'toolslm.funccall.get_schema': ('funccall.html#get_schema', 'toolslm/funccall.py'),
13
+ 'toolslm.funccall.python': ('funccall.html#python', 'toolslm/funccall.py')},
11
14
  'toolslm.shell': { 'toolslm.shell.TerminalInteractiveShell.run_cell': ( 'shell.html#terminalinteractiveshell.run_cell',
12
15
  'toolslm/shell.py'),
13
16
  'toolslm.shell.get_shell': ('shell.html#get_shell', 'toolslm/shell.py')},
@@ -15,9 +18,7 @@ d = { 'settings': { 'branch': 'main',
15
18
  'toolslm.xml.docs_xml': ('xml.html#docs_xml', 'toolslm/xml.py'),
16
19
  'toolslm.xml.files2ctx': ('xml.html#files2ctx', 'toolslm/xml.py'),
17
20
  'toolslm.xml.folder2ctx': ('xml.html#folder2ctx', 'toolslm/xml.py'),
18
- 'toolslm.xml.hl_md': ('xml.html#hl_md', 'toolslm/xml.py'),
21
+ 'toolslm.xml.folder2ctx_cli': ('xml.html#folder2ctx_cli', 'toolslm/xml.py'),
19
22
  'toolslm.xml.json_to_xml': ('xml.html#json_to_xml', 'toolslm/xml.py'),
20
23
  'toolslm.xml.mk_doc': ('xml.html#mk_doc', 'toolslm/xml.py'),
21
- 'toolslm.xml.mk_doctype': ('xml.html#mk_doctype', 'toolslm/xml.py'),
22
- 'toolslm.xml.to_xml': ('xml.html#to_xml', 'toolslm/xml.py'),
23
- 'toolslm.xml.xt': ('xml.html#xt', 'toolslm/xml.py')}}}
24
+ 'toolslm.xml.mk_doctype': ('xml.html#mk_doctype', 'toolslm/xml.py')}}}
toolslm/funccall.py ADDED
@@ -0,0 +1,95 @@
1
+ # AUTOGENERATED! DO NOT EDIT! File to edit: ../01_funccall.ipynb.
2
+
3
+ # %% auto 0
4
+ __all__ = ['empty', 'get_schema', 'python']
5
+
6
+ # %% ../01_funccall.ipynb 2
7
+ import inspect
8
+ from fastcore.utils import *
9
+ from fastcore.docments import docments
10
+
11
+ # %% ../01_funccall.ipynb 3
12
+ empty = inspect.Parameter.empty
13
+
14
+ # %% ../01_funccall.ipynb 11
15
+ def _types(t:type)->tuple[str,Optional[str]]:
16
+ "Tuple of json schema type name and (if appropriate) array item name."
17
+ if t is empty: raise TypeError('Missing type')
18
+ tmap = {int:"integer", float:"number", str:"string", bool:"boolean", list:"array", dict:"object"}
19
+ if getattr(t, '__origin__', None) in (list,tuple): return "array", tmap.get(t.__args__[0], "object")
20
+ else: return tmap[t], None
21
+
22
+ # %% ../01_funccall.ipynb 14
23
+ def _param(name, info):
24
+ "json schema parameter given `name` and `info` from docments full dict."
25
+ paramt,itemt = _types(info.anno)
26
+ pschema = dict(type=paramt, description=info.docment or "")
27
+ if itemt: pschema["items"] = {"type": itemt}
28
+ if info.default is not empty: pschema["default"] = info.default
29
+ return pschema
30
+
31
+ # %% ../01_funccall.ipynb 17
32
+ def get_schema(f:callable, pname='input_schema')->dict:
33
+ "Convert function `f` into a JSON schema `dict` for tool use."
34
+ d = docments(f, full=True)
35
+ ret = d.pop('return')
36
+ d.pop('self', None) # Ignore `self` for methods
37
+ paramd = {
38
+ 'type': "object",
39
+ 'properties': {n:_param(n,o) for n,o in d.items() if n[0]!='_'},
40
+ 'required': [n for n,o in d.items() if o.default is empty and n[0]!='_']
41
+ }
42
+ desc = f.__doc__
43
+ assert desc, "Docstring missing!"
44
+ if ret.anno is not empty: desc += f'\n\nReturns:\n- type: {_types(ret.anno)[0]}'
45
+ if ret.docment: desc += f'\n- description: {ret.docment}'
46
+ return {'name':f.__name__, 'description':desc, pname:paramd}
47
+
48
+ # %% ../01_funccall.ipynb 22
49
+ import ast, time, signal, traceback
50
+ from fastcore.utils import *
51
+
52
+ # %% ../01_funccall.ipynb 23
53
+ def _copy_loc(new, orig):
54
+ "Copy location information from original node to new node and all children."
55
+ new = ast.copy_location(new, orig)
56
+ for field, o in ast.iter_fields(new):
57
+ if isinstance(o, ast.AST): setattr(new, field, _copy_loc(o, orig))
58
+ elif isinstance(o, list): setattr(new, field, [_copy_loc(value, orig) for value in o])
59
+ return new
60
+
61
+ # %% ../01_funccall.ipynb 25
62
+ def _run(code:str ):
63
+ "Run `code`, returning final expression (similar to IPython)"
64
+ tree = ast.parse(code)
65
+ last_node = tree.body[-1] if tree.body else None
66
+
67
+ # If the last node is an expression, modify the AST to capture the result
68
+ if isinstance(last_node, ast.Expr):
69
+ tgt = [ast.Name(id='_result', ctx=ast.Store())]
70
+ assign_node = ast.Assign(targets=tgt, value=last_node.value)
71
+ tree.body[-1] = _copy_loc(assign_node, last_node)
72
+
73
+ compiled_code = compile(tree, filename='<ast>', mode='exec')
74
+ namespace = {}
75
+ stdout_buffer = io.StringIO()
76
+ saved_stdout = sys.stdout
77
+ sys.stdout = stdout_buffer
78
+ try: exec(compiled_code, namespace)
79
+ finally: sys.stdout = saved_stdout
80
+ _result = namespace.get('_result', None)
81
+ if _result is not None: return _result
82
+ return stdout_buffer.getvalue().strip()
83
+
84
+ # %% ../01_funccall.ipynb 30
85
+ def python(code, # Code to execute
86
+ timeout=5 # Maximum run time in seconds before a `TimeoutError` is raised
87
+ ): # Result of last node, if it's an expression, or `None` otherwise
88
+ """Executes python `code` with `timeout` and returning final expression (similar to IPython).
89
+ Raised exceptions are returned as a string, with a stack trace."""
90
+ def handler(*args): raise TimeoutError()
91
+ signal.signal(signal.SIGALRM, handler)
92
+ signal.alarm(timeout)
93
+ try: return _run(code)
94
+ except Exception as e: return traceback.format_exc()
95
+ finally: signal.alarm(0)
toolslm/xml.py CHANGED
@@ -1,8 +1,7 @@
1
1
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../00_xml.ipynb.
2
2
 
3
3
  # %% auto 0
4
- __all__ = ['g', 'tags', 'doctype', 'xt', 'hl_md', 'to_xml', 'json_to_xml', 'mk_doctype', 'mk_doc', 'docs_xml', 'files2ctx',
5
- 'folder2ctx']
4
+ __all__ = ['doctype', 'json_to_xml', 'mk_doctype', 'mk_doc', 'docs_xml', 'files2ctx', 'folder2ctx', 'folder2ctx_cli']
6
5
 
7
6
  # %% ../00_xml.ipynb 3
8
7
  import hashlib,xml.etree.ElementTree as ET
@@ -10,45 +9,13 @@ from collections import namedtuple
10
9
 
11
10
  from fastcore.utils import *
12
11
  from fastcore.meta import delegates
12
+ from fastcore.xtras import hl_md
13
+ from fastcore.xml import to_xml, Document, Documents, Document_content, Source
14
+ from fastcore.script import call_parse
13
15
  try: from IPython import display
14
16
  except: display=None
15
17
 
16
- # %% ../00_xml.ipynb 6
17
- def xt(tag:str, # XML tag name
18
- c:Optional[list]=None, # Children
19
- **kw):
20
- "Helper to create appropriate data structure for `to_xml`."
21
- kw = {k.lstrip('_'):str(v) for k,v in kw.items()}
22
- return tag,c,kw
23
-
24
- # %% ../00_xml.ipynb 9
25
- g = globals()
26
- tags = 'div img h1 h2 h3 h4 h5 p hr span html'.split()
27
- for o in tags: g[o] = partial(xt, o)
28
-
29
- # %% ../00_xml.ipynb 12
30
- def hl_md(s, lang='xml'):
31
- "Syntax highlight `s` using `lang`."
32
- if display: return display.Markdown(f'```{lang}\n{s}\n```')
33
- print(s)
34
-
35
- # %% ../00_xml.ipynb 15
36
- def to_xml(node:tuple, # XML structure in `xt` format
37
- hl=False # Syntax highlight response?
38
- ):
39
- "Convert `node` to an XML string."
40
- def mk_el(tag, cs, attrs):
41
- el = ET.Element(tag, attrib=attrs)
42
- if isinstance(cs, list): el.extend([mk_el(*o) for o in cs])
43
- elif cs is not None: el.text = str(cs)
44
- return el
45
-
46
- root = mk_el(*node)
47
- ET.indent(root, space=' ' if hl else '')
48
- res = ET.tostring(root, encoding='unicode')
49
- return hl_md(res) if hl else res
50
-
51
- # %% ../00_xml.ipynb 18
18
+ # %% ../00_xml.ipynb 4
52
19
  def json_to_xml(d:dict, # JSON dictionary to convert
53
20
  rnm:str # Root name
54
21
  )->str:
@@ -64,17 +31,17 @@ def json_to_xml(d:dict, # JSON dictionary to convert
64
31
  ET.indent(root)
65
32
  return ET.tostring(root, encoding='unicode')
66
33
 
67
- # %% ../00_xml.ipynb 23
34
+ # %% ../00_xml.ipynb 9
68
35
  doctype = namedtuple('doctype', ['source', 'content'])
69
36
 
70
- # %% ../00_xml.ipynb 25
37
+ # %% ../00_xml.ipynb 11
71
38
  def _add_nls(s):
72
39
  "Add newlines to start and end of `s` if missing"
73
40
  if s[ 0]!='\n': s = '\n'+s
74
41
  if s[-1]!='\n': s = s+'\n'
75
42
  return s
76
43
 
77
- # %% ../00_xml.ipynb 27
44
+ # %% ../00_xml.ipynb 13
78
45
  def mk_doctype(content:str, # The document content
79
46
  source:Optional[str]=None # URL, filename, etc; defaults to `md5(content)` if not provided
80
47
  ) -> namedtuple:
@@ -82,18 +49,29 @@ def mk_doctype(content:str, # The document content
82
49
  if source is None: source = hashlib.md5(content.encode()).hexdigest()[:8]
83
50
  return doctype(_add_nls(str(source).strip()), _add_nls(content.strip()))
84
51
 
85
- # %% ../00_xml.ipynb 30
52
+ # %% ../00_xml.ipynb 17
86
53
  def mk_doc(index:int, # The document index
87
54
  content:str, # The document content
88
55
  source:Optional[str]=None # URL, filename, etc; defaults to `md5(content)` if not provided
89
56
  ) -> tuple:
90
- "Create an `xt` format tuple for a single doc in Anthropic's recommended format"
57
+ "Create an `ft` format tuple for a single doc in Anthropic's recommended format"
91
58
  dt = mk_doctype(content, source)
92
- content = xt('document_content', dt.content)
93
- source = xt('source', dt.source)
94
- return xt('document', [source, content], index=index)
59
+ content = ft('document_content', dt.content)
60
+ source = ft('source', dt.source)
61
+ return ft('document', source, content, index=index)
95
62
 
96
- # %% ../00_xml.ipynb 33
63
+ # %% ../00_xml.ipynb 18
64
+ def mk_doc(index:int, # The document index
65
+ content:str, # The document content
66
+ source:Optional[str]=None # URL, filename, etc; defaults to `md5(content)` if not provided
67
+ ) -> tuple:
68
+ "Create an `ft` format tuple for a single doc in Anthropic's recommended format"
69
+ dt = mk_doctype(content, source)
70
+ content = Document_content(dt.content)
71
+ source = Source(dt.source)
72
+ return Document(source, content, index=index)
73
+
74
+ # %% ../00_xml.ipynb 22
97
75
  def docs_xml(docs:list[str], # The content of each document
98
76
  sources:Optional[list]=None, # URLs, filenames, etc; each one defaults to `md5(content)` if not provided
99
77
  prefix:bool=True # Include Anthropic's suggested prose intro?
@@ -101,10 +79,10 @@ def docs_xml(docs:list[str], # The content of each document
101
79
  "Create an XML string containing `docs` in Anthropic's recommended format"
102
80
  pre = 'Here are some documents for you to reference for your task:\n\n' if prefix else ''
103
81
  if sources is None: sources = [None]*len(docs)
104
- docs = [mk_doc(i+1, *o) for i,o in enumerate(zip(docs,sources))]
105
- return pre + to_xml(xt('documents', docs))
82
+ docs = (mk_doc(i+1, *o) for i,o in enumerate(zip(docs,sources)))
83
+ return pre + to_xml(Documents(docs))
106
84
 
107
- # %% ../00_xml.ipynb 40
85
+ # %% ../00_xml.ipynb 29
108
86
  def files2ctx(
109
87
  fnames:list[Union[str,Path]], # List of file names to add to context
110
88
  prefix:bool=True # Include Anthropic's suggested prose intro?
@@ -113,7 +91,7 @@ def files2ctx(
113
91
  contents = [o.read_text() for o in fnames]
114
92
  return docs_xml(contents, fnames, prefix=prefix)
115
93
 
116
- # %% ../00_xml.ipynb 43
94
+ # %% ../00_xml.ipynb 32
117
95
  @delegates(globtastic)
118
96
  def folder2ctx(
119
97
  folder:Union[str,Path], # Folder name containing files to add to context
@@ -122,3 +100,12 @@ def folder2ctx(
122
100
  )->str: # XML for Claude context
123
101
  fnames = globtastic(folder, **kwargs)
124
102
  return files2ctx(fnames, prefix=prefix)
103
+
104
+ # %% ../00_xml.ipynb 34
105
+ @call_parse
106
+ @delegates(folder2ctx)
107
+ def folder2ctx_cli(
108
+ folder:str, # Folder name containing files to add to context
109
+ **kwargs # Passed to `folder2ctx`
110
+ )->str: # XML for Claude context
111
+ return folder2ctx(folder, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: toolslm
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Tools to make language models a bit easier to use
5
5
  Home-page: https://github.com/AnswerDotAI/toolslm
6
6
  Author: Jeremy Howard
@@ -16,7 +16,7 @@ Classifier: License :: OSI Approved :: Apache Software License
16
16
  Requires-Python: >=3.9
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: fastcore
19
+ Requires-Dist: fastcore >=1.5.47
20
20
  Provides-Extra: dev
21
21
 
22
22
  # toolslm
@@ -0,0 +1,11 @@
1
+ toolslm/__init__.py,sha256=1mptEzQihbdyqqzMgdns_j5ZGK9gz7hR2bsgA_TnjO4,22
2
+ toolslm/_modidx.py,sha256=6T36Q2cYKH0lp9Tt9Us8xpZV-Z0FYqrtZGu2ZykHDkg,2068
3
+ toolslm/funccall.py,sha256=mzWNLdZY6cYk-I3O5noRiEB089mPwJhnRQFsS5_JYDs,3856
4
+ toolslm/shell.py,sha256=GVqfL74NHw66zzZ7jvGVLjE55ZNJGBPvEb8kLz4aoYc,1576
5
+ toolslm/xml.py,sha256=dSJOHqSWnZlMK1Qf3396ISSaBHf5miNlLSYCixYB9ng,4398
6
+ toolslm-0.0.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
7
+ toolslm-0.0.4.dist-info/METADATA,sha256=9Ni6CdLgvxTCx7LqIrnNyUgrfu0t2Wsdabp9jZlFNvw,3782
8
+ toolslm-0.0.4.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
9
+ toolslm-0.0.4.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
10
+ toolslm-0.0.4.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
11
+ toolslm-0.0.4.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ folder2ctx = toolslm.xml:folder2ctx_cli
3
+
4
+ [nbdev]
5
+ toolslm = toolslm._modidx:d
toolslm/lmcode.py DELETED
@@ -1,53 +0,0 @@
1
- # AUTOGENERATED! DO NOT EDIT! File to edit: ../01_lmcode.ipynb.
2
-
3
- # %% auto 0
4
- __all__ = ['python']
5
-
6
- # %% ../01_lmcode.ipynb 3
7
- import ast, time, signal, traceback
8
- from fastcore.utils import *
9
-
10
- # %% ../01_lmcode.ipynb 5
11
- def _copy_loc(new, orig):
12
- "Copy location information from original node to new node and all children."
13
- new = ast.copy_location(new, orig)
14
- for field, o in ast.iter_fields(new):
15
- if isinstance(o, ast.AST): setattr(new, field, _copy_loc(o, orig))
16
- elif isinstance(o, list): setattr(new, field, [_copy_loc(value, orig) for value in o])
17
- return new
18
-
19
- # %% ../01_lmcode.ipynb 7
20
- def _run(code:str ):
21
- "Run `code`, returning final expression (similar to IPython)"
22
- tree = ast.parse(code)
23
- last_node = tree.body[-1] if tree.body else None
24
-
25
- # If the last node is an expression, modify the AST to capture the result
26
- if isinstance(last_node, ast.Expr):
27
- tgt = [ast.Name(id='_result', ctx=ast.Store())]
28
- assign_node = ast.Assign(targets=tgt, value=last_node.value)
29
- tree.body[-1] = _copy_loc(assign_node, last_node)
30
-
31
- compiled_code = compile(tree, filename='<ast>', mode='exec')
32
- namespace = {}
33
- stdout_buffer = io.StringIO()
34
- saved_stdout = sys.stdout
35
- sys.stdout = stdout_buffer
36
- try: exec(compiled_code, namespace)
37
- finally: sys.stdout = saved_stdout
38
- _result = namespace.get('_result', None)
39
- if _result is not None: return _result
40
- return stdout_buffer.getvalue().strip()
41
-
42
- # %% ../01_lmcode.ipynb 12
43
- def python(code, # Code to execute
44
- timeout=5 # Maximum run time in seconds before a `TimeoutError` is raised
45
- ): # Result of last node, if it's an expression, or `None` otherwise
46
- """Executes python `code` with `timeout` and returning final expression (similar to IPython).
47
- Raised exceptions are returned as a string, with a stack trace."""
48
- def handler(*args): raise TimeoutError()
49
- signal.signal(signal.SIGALRM, handler)
50
- signal.alarm(timeout)
51
- try: return _run(code)
52
- except Exception as e: return traceback.format_exc()
53
- finally: signal.alarm(0)
@@ -1,11 +0,0 @@
1
- toolslm/__init__.py,sha256=QvlVh4JTl3JL7jQAja76yKtT-IvF4631ASjWY1wS6AQ,22
2
- toolslm/_modidx.py,sha256=fmKi8RF2pdYu9iFlVY__PTCgOTaWgWYqUfrQBjimhxA,1860
3
- toolslm/lmcode.py,sha256=G28x34SsxQPGhSNGHggXh6dWaeGlxQH69nAu9tgdNF8,2104
4
- toolslm/shell.py,sha256=GVqfL74NHw66zzZ7jvGVLjE55ZNJGBPvEb8kLz4aoYc,1576
5
- toolslm/xml.py,sha256=4DnFUYG09fB1ZTzcyeugKdkMU40MMMf3zZEHbDfSGIo,4635
6
- toolslm-0.0.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
7
- toolslm-0.0.2.dist-info/METADATA,sha256=KHlZaY6NAr7a0DCNTeq6rHxaJO5cze8jciBAT4Z7C-g,3773
8
- toolslm-0.0.2.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
9
- toolslm-0.0.2.dist-info/entry_points.txt,sha256=3os5YWuvVIFuweYaNtnwgv-xCe4Gb1KcZndFz8KWI0E,36
10
- toolslm-0.0.2.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
11
- toolslm-0.0.2.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [nbdev]
2
- toolslm = toolslm._modidx:d