toolslm 0.3.3__py3-none-any.whl → 0.3.9__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 +1 -1
- toolslm/_modidx.py +7 -3
- toolslm/funccall.py +56 -12
- toolslm/md_hier.py +35 -6
- toolslm/xml.py +69 -27
- {toolslm-0.3.3.dist-info → toolslm-0.3.9.dist-info}/METADATA +2 -2
- toolslm-0.3.9.dist-info/RECORD +13 -0
- toolslm-0.3.3.dist-info/RECORD +0 -13
- {toolslm-0.3.3.dist-info → toolslm-0.3.9.dist-info}/WHEEL +0 -0
- {toolslm-0.3.3.dist-info → toolslm-0.3.9.dist-info}/entry_points.txt +0 -0
- {toolslm-0.3.3.dist-info → toolslm-0.3.9.dist-info}/licenses/LICENSE +0 -0
- {toolslm-0.3.3.dist-info → toolslm-0.3.9.dist-info}/top_level.txt +0 -0
toolslm/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.3.
|
|
1
|
+
__version__ = "0.3.9"
|
toolslm/_modidx.py
CHANGED
|
@@ -14,7 +14,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
14
14
|
'toolslm.download.read_html': ('download.html#read_html', 'toolslm/download.py'),
|
|
15
15
|
'toolslm.download.read_md': ('download.html#read_md', 'toolslm/download.py'),
|
|
16
16
|
'toolslm.download.split_url': ('download.html#split_url', 'toolslm/download.py')},
|
|
17
|
-
'toolslm.funccall': { 'toolslm.funccall.
|
|
17
|
+
'toolslm.funccall': { 'toolslm.funccall._coerce_inputs': ('funccall.html#_coerce_inputs', 'toolslm/funccall.py'),
|
|
18
18
|
'toolslm.funccall._copy_loc': ('funccall.html#_copy_loc', 'toolslm/funccall.py'),
|
|
19
19
|
'toolslm.funccall._get_nested_schema': ('funccall.html#_get_nested_schema', 'toolslm/funccall.py'),
|
|
20
20
|
'toolslm.funccall._handle_container': ('funccall.html#_handle_container', 'toolslm/funccall.py'),
|
|
@@ -29,7 +29,10 @@ d = { 'settings': { 'branch': 'main',
|
|
|
29
29
|
'toolslm.funccall.call_func_async': ('funccall.html#call_func_async', 'toolslm/funccall.py'),
|
|
30
30
|
'toolslm.funccall.get_schema': ('funccall.html#get_schema', 'toolslm/funccall.py'),
|
|
31
31
|
'toolslm.funccall.mk_ns': ('funccall.html#mk_ns', 'toolslm/funccall.py'),
|
|
32
|
-
'toolslm.funccall.
|
|
32
|
+
'toolslm.funccall.mk_param': ('funccall.html#mk_param', 'toolslm/funccall.py'),
|
|
33
|
+
'toolslm.funccall.mk_tool': ('funccall.html#mk_tool', 'toolslm/funccall.py'),
|
|
34
|
+
'toolslm.funccall.python': ('funccall.html#python', 'toolslm/funccall.py'),
|
|
35
|
+
'toolslm.funccall.schema2sig': ('funccall.html#schema2sig', 'toolslm/funccall.py')},
|
|
33
36
|
'toolslm.md_hier': {},
|
|
34
37
|
'toolslm.shell': { 'toolslm.shell.TerminalInteractiveShell.run_cell': ( 'shell.html#terminalinteractiveshell.run_cell',
|
|
35
38
|
'toolslm/shell.py'),
|
|
@@ -46,4 +49,5 @@ d = { 'settings': { 'branch': 'main',
|
|
|
46
49
|
'toolslm.xml.mk_doc': ('xml.html#mk_doc', 'toolslm/xml.py'),
|
|
47
50
|
'toolslm.xml.mk_doctype': ('xml.html#mk_doctype', 'toolslm/xml.py'),
|
|
48
51
|
'toolslm.xml.nb2xml': ('xml.html#nb2xml', 'toolslm/xml.py'),
|
|
49
|
-
'toolslm.xml.read_file': ('xml.html#read_file', 'toolslm/xml.py')
|
|
52
|
+
'toolslm.xml.read_file': ('xml.html#read_file', 'toolslm/xml.py'),
|
|
53
|
+
'toolslm.xml.repo2ctx': ('xml.html#repo2ctx', 'toolslm/xml.py')}}}
|
toolslm/funccall.py
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../01_funccall.ipynb.
|
|
2
2
|
|
|
3
3
|
# %% auto 0
|
|
4
|
-
__all__ = ['empty', 'custom_types', 'get_schema', '
|
|
4
|
+
__all__ = ['empty', 'custom_types', 'get_schema', 'python', 'mk_ns', 'call_func', 'call_func_async', 'mk_param', 'schema2sig',
|
|
5
|
+
'mk_tool']
|
|
5
6
|
|
|
6
7
|
# %% ../01_funccall.ipynb
|
|
7
|
-
import inspect
|
|
8
|
+
import inspect, json
|
|
8
9
|
from collections import abc
|
|
9
10
|
from fastcore.utils import *
|
|
10
11
|
from fastcore.docments import docments
|
|
11
|
-
from typing import get_origin, get_args, Dict, List, Optional, Tuple, Union
|
|
12
|
+
from typing import get_origin, get_args, Dict, List, Optional, Tuple, Union, Any
|
|
12
13
|
from types import UnionType
|
|
14
|
+
from typing import get_type_hints
|
|
15
|
+
from inspect import Parameter, Signature
|
|
16
|
+
from decimal import Decimal
|
|
17
|
+
from uuid import UUID
|
|
13
18
|
|
|
14
19
|
# %% ../01_funccall.ipynb
|
|
15
20
|
empty = inspect.Parameter.empty
|
|
@@ -41,7 +46,7 @@ def _param(name, info):
|
|
|
41
46
|
return pschema
|
|
42
47
|
|
|
43
48
|
# %% ../01_funccall.ipynb
|
|
44
|
-
custom_types = {Path}
|
|
49
|
+
custom_types = {Path, bytes, Decimal, UUID}
|
|
45
50
|
|
|
46
51
|
def _handle_type(t, defs):
|
|
47
52
|
"Handle a single type, creating nested schemas if necessary"
|
|
@@ -123,14 +128,9 @@ def get_schema(f:Union[callable,dict], pname='input_schema')->dict:
|
|
|
123
128
|
assert desc, "Docstring missing!"
|
|
124
129
|
d = docments(f, full=True)
|
|
125
130
|
ret = d.pop('return')
|
|
126
|
-
if ret.anno is not empty: desc += f'\n\nReturns:\n- type: {_types(ret.anno)[0]}'
|
|
131
|
+
if (ret.anno is not empty) and (ret.anno is not None): desc += f'\n\nReturns:\n- type: {_types(ret.anno)[0]}'
|
|
127
132
|
return {"name": f.__name__, "description": desc, pname: schema}
|
|
128
133
|
|
|
129
|
-
# %% ../01_funccall.ipynb
|
|
130
|
-
def PathArg(
|
|
131
|
-
path: str # A filesystem path
|
|
132
|
-
): return Path(path)
|
|
133
|
-
|
|
134
134
|
# %% ../01_funccall.ipynb
|
|
135
135
|
import ast, time, signal, traceback
|
|
136
136
|
from fastcore.utils import *
|
|
@@ -193,14 +193,26 @@ def mk_ns(fs):
|
|
|
193
193
|
elif callable(o) and hasattr(o, '__name__'): merged |= {o.__name__: o}
|
|
194
194
|
return merged
|
|
195
195
|
|
|
196
|
+
# %% ../01_funccall.ipynb
|
|
197
|
+
def _coerce_inputs(func, inputs):
|
|
198
|
+
"Coerce inputs based on function type annotations"
|
|
199
|
+
hints = get_type_hints(func) if hasattr(func, '__annotations__') else {}
|
|
200
|
+
res = {}
|
|
201
|
+
for k,v in inputs.items():
|
|
202
|
+
ann = hints.get(k)
|
|
203
|
+
if ann in custom_types: res[k] = ann(v)
|
|
204
|
+
elif isinstance(v, dict) and callable(ann): res[k] = ann(**v)
|
|
205
|
+
else: res[k] = v
|
|
206
|
+
return res
|
|
207
|
+
|
|
196
208
|
# %% ../01_funccall.ipynb
|
|
197
209
|
def call_func(fc_name, fc_inputs, ns, raise_on_err=True):
|
|
198
210
|
"Call the function `fc_name` with the given `fc_inputs` using namespace `ns`."
|
|
199
211
|
if not isinstance(ns, abc.Mapping): ns = mk_ns(ns)
|
|
200
212
|
func = ns[fc_name]
|
|
201
|
-
# Clean up bad param names
|
|
202
213
|
inps = {re.sub(r'\W', '', k):v for k,v in fc_inputs.items()}
|
|
203
|
-
|
|
214
|
+
inps = _coerce_inputs(func, inps)
|
|
215
|
+
try: return func(**inps)
|
|
204
216
|
except Exception as e:
|
|
205
217
|
if raise_on_err: raise e from None
|
|
206
218
|
else: return traceback.format_exc()
|
|
@@ -215,3 +227,35 @@ async def call_func_async(fc_name, fc_inputs, ns, raise_on_err=True):
|
|
|
215
227
|
if raise_on_err: raise e from None
|
|
216
228
|
else: return traceback.format_exc()
|
|
217
229
|
return res
|
|
230
|
+
|
|
231
|
+
# %% ../01_funccall.ipynb
|
|
232
|
+
def mk_param(nm, props, req):
|
|
233
|
+
"Create a `Parameter` for `nm` with schema `props`"
|
|
234
|
+
kind = Parameter.POSITIONAL_OR_KEYWORD if nm in req else Parameter.KEYWORD_ONLY
|
|
235
|
+
default = Parameter.empty if nm in req else props.get('default')
|
|
236
|
+
if props.get('type') == 'array' and 'items' in props:
|
|
237
|
+
item_type = type_map.get(props['items'].get('type'), Any)
|
|
238
|
+
anno = list[item_type]
|
|
239
|
+
else: anno = type_map.get(props.get('type'), Any)
|
|
240
|
+
return Parameter(nm, kind, default=default, annotation=anno)
|
|
241
|
+
|
|
242
|
+
# %% ../01_funccall.ipynb
|
|
243
|
+
def schema2sig(tool):
|
|
244
|
+
"Convert json schema `tool` to a `Signature`"
|
|
245
|
+
props, req = tool.inputSchema['properties'], tool.inputSchema.get('required', [])
|
|
246
|
+
params = sorted([mk_param(k, v, req) for k, v in props.items()], key=lambda p: p.kind)
|
|
247
|
+
return Signature(params)
|
|
248
|
+
|
|
249
|
+
# %% ../01_funccall.ipynb
|
|
250
|
+
def mk_tool(dispfn, tool):
|
|
251
|
+
"Create a callable function from a JSON schema tool definition"
|
|
252
|
+
sig = schema2sig(tool)
|
|
253
|
+
props = tool.inputSchema['properties']
|
|
254
|
+
def fn(*args, **kwargs):
|
|
255
|
+
bound = sig.bind(*args, **kwargs)
|
|
256
|
+
return dispfn(tool.name, **bound.arguments)
|
|
257
|
+
fn.__doc__ = tool.description
|
|
258
|
+
fn.__signature__ = sig
|
|
259
|
+
fn.__name__ = fn.__qualname__ = tool.name
|
|
260
|
+
fn.__annotations__ = {k: p.annotation for k, p in sig.parameters.items()}
|
|
261
|
+
return fn
|
toolslm/md_hier.py
CHANGED
|
@@ -14,20 +14,32 @@ def create_heading_dict(text, rm_fenced=True):
|
|
|
14
14
|
original_text = text
|
|
15
15
|
original_lines = text.splitlines()
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
# Build line mapping when removing fenced blocks
|
|
18
|
+
if rm_fenced:
|
|
19
|
+
filtered_lines,original_line_map,in_fenced = [],{},False
|
|
20
|
+
for i, line in enumerate(original_lines):
|
|
21
|
+
if line.strip().startswith('```'):
|
|
22
|
+
in_fenced = not in_fenced
|
|
23
|
+
continue
|
|
24
|
+
if not in_fenced:
|
|
25
|
+
original_line_map[len(filtered_lines)] = i
|
|
26
|
+
filtered_lines.append(line)
|
|
27
|
+
|
|
28
|
+
lines_for_headings = filtered_lines
|
|
29
|
+
else:
|
|
30
|
+
lines_for_headings = original_lines
|
|
31
|
+
original_line_map = {i: i for i in range(len(original_lines))}
|
|
20
32
|
|
|
21
|
-
lines_for_headings = text_for_headings.splitlines()
|
|
22
33
|
headings = []
|
|
23
34
|
|
|
24
|
-
# Parse headings with their levels and line numbers
|
|
35
|
+
# Parse headings with their levels and original line numbers
|
|
25
36
|
for idx, line in enumerate(lines_for_headings):
|
|
26
37
|
match = re.match(r'^(#{1,6})\s+\S.*', line)
|
|
27
38
|
if match:
|
|
28
39
|
level = len(match.group(1))
|
|
29
40
|
title = line.strip('#').strip()
|
|
30
|
-
|
|
41
|
+
original_line_idx = original_line_map[idx]
|
|
42
|
+
headings.append({'level': level, 'title': title, 'line': original_line_idx})
|
|
31
43
|
|
|
32
44
|
# Assign text content to each heading using original lines
|
|
33
45
|
for i, h in enumerate(headings):
|
|
@@ -270,9 +282,26 @@ More content after code."""
|
|
|
270
282
|
assert '💻 Computer' in result['🚀 Rocket Heading']
|
|
271
283
|
assert result.text == md_content
|
|
272
284
|
|
|
285
|
+
def test_fenced_blocks_between_headings():
|
|
286
|
+
md_content = """# First Header
|
|
287
|
+
Content here.
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
# A comment that should be ignored for structure
|
|
291
|
+
def example():
|
|
292
|
+
pass
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
# Second Header
|
|
296
|
+
This content belongs to Second Header."""
|
|
297
|
+
result = create_heading_dict(md_content)
|
|
298
|
+
assert "def example():" not in result['Second Header'].text
|
|
299
|
+
assert result['Second Header'].text == "# Second Header\nThis content belongs to Second Header."
|
|
300
|
+
|
|
273
301
|
test_empty_input()
|
|
274
302
|
test_whitespace_only()
|
|
275
303
|
test_malformed_headings()
|
|
276
304
|
test_unicode_and_emojis()
|
|
305
|
+
test_fenced_blocks_between_headings()
|
|
277
306
|
print('tests passed')
|
|
278
307
|
|
toolslm/xml.py
CHANGED
|
@@ -2,19 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
# %% auto 0
|
|
4
4
|
__all__ = ['doctype', 'json_to_xml', 'get_mime_text', 'cell2out', 'cell2xml', 'nb2xml', 'mk_doctype', 'mk_doc', 'docs_xml',
|
|
5
|
-
'read_file', 'files2ctx', 'folder2ctx', 'folder2ctx_cli']
|
|
5
|
+
'read_file', 'files2ctx', 'folder2ctx', 'repo2ctx', 'folder2ctx_cli']
|
|
6
6
|
|
|
7
7
|
# %% ../00_xml.ipynb
|
|
8
8
|
import hashlib,xml.etree.ElementTree as ET
|
|
9
9
|
from collections import namedtuple
|
|
10
|
+
from ghapi.all import GhApi
|
|
10
11
|
|
|
11
12
|
from fastcore.utils import *
|
|
12
13
|
from fastcore.meta import delegates
|
|
13
14
|
from fastcore.xtras import hl_md
|
|
14
|
-
from fastcore.xml import to_xml, Document, Documents, Document_content, Src, Source,Out,Outs,Cell
|
|
15
|
+
from fastcore.xml import to_xml, Document, Documents, Document_content, Src, Source,Out,Outs,Cell,Notebook,Md,Code
|
|
15
16
|
from fastcore.script import call_parse
|
|
16
|
-
try: from IPython import display
|
|
17
|
-
except: display=None
|
|
18
17
|
|
|
19
18
|
# %% ../00_xml.ipynb
|
|
20
19
|
def json_to_xml(d:dict, # JSON dictionary to convert
|
|
@@ -50,20 +49,23 @@ def cell2out(o):
|
|
|
50
49
|
if hasattr(o, 'ename'): return Out(f"{o.ename}: {o.evalue}", type='error')
|
|
51
50
|
|
|
52
51
|
# %% ../00_xml.ipynb
|
|
53
|
-
def cell2xml(cell):
|
|
52
|
+
def cell2xml(cell, out=True):
|
|
54
53
|
"Convert notebook cell to concise XML format"
|
|
55
|
-
|
|
54
|
+
src = ''.join(getattr(cell, 'source', ''))
|
|
55
|
+
f = Code if cell.cell_type=='code' else Md
|
|
56
|
+
if not out: return f(src)
|
|
57
|
+
parts = [Source(src)]
|
|
56
58
|
out_items = L(getattr(cell,'outputs',[])).map(cell2out).filter()
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
parts = [p for p in [cts, outs] if p]
|
|
60
|
-
return Cell(*parts, type=cell.cell_type)
|
|
59
|
+
if out_items: parts.append(Outs(*out_items))
|
|
60
|
+
return f(*parts)
|
|
61
61
|
|
|
62
62
|
# %% ../00_xml.ipynb
|
|
63
|
-
def nb2xml(fname):
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
def nb2xml(fname=None, nb=None, out=True):
|
|
64
|
+
"Convert notebook to XML format"
|
|
65
|
+
assert bool(fname)^bool(nb), "Pass either `fname` or `nb`"
|
|
66
|
+
if not nb: nb = dict2obj(fname.read_json())
|
|
67
|
+
cells_xml = [to_xml(cell2xml(c, out=out), do_escape=False) for c in nb.cells if c.cell_type in ('code','markdown')]
|
|
68
|
+
return to_xml(Notebook(*cells_xml), do_escape=False)
|
|
67
69
|
|
|
68
70
|
# %% ../00_xml.ipynb
|
|
69
71
|
doctype = namedtuple('doctype', ['src', 'content'])
|
|
@@ -100,47 +102,87 @@ def mk_doc(index:int, # The document index
|
|
|
100
102
|
def docs_xml(docs:list[str], # The content of each document
|
|
101
103
|
srcs:Optional[list]=None, # URLs, filenames, etc; each one defaults to `md5(content)` if not provided
|
|
102
104
|
prefix:bool=True, # Include Anthropic's suggested prose intro?
|
|
103
|
-
details:Optional[list]=None # Optional list of dicts with additional attrs for each doc
|
|
105
|
+
details:Optional[list]=None, # Optional list of dicts with additional attrs for each doc
|
|
106
|
+
title:str=None # Optional title attr for Documents element
|
|
104
107
|
)->str:
|
|
105
108
|
"Create an XML string containing `docs` in Anthropic's recommended format"
|
|
106
109
|
pre = 'Here are some documents for you to reference for your task:\n\n' if prefix else ''
|
|
107
110
|
if srcs is None: srcs = [None]*len(docs)
|
|
108
111
|
if details is None: details = [{}]*len(docs)
|
|
109
112
|
docs = (mk_doc(i+1, d, s, **kw) for i,(d,s,kw) in enumerate(zip(docs,srcs,details)))
|
|
110
|
-
|
|
113
|
+
kw = dict(title=title) if title else {}
|
|
114
|
+
return pre + to_xml(Documents(*docs, **kw), do_escape=False)
|
|
111
115
|
|
|
112
116
|
# %% ../00_xml.ipynb
|
|
113
|
-
def read_file(fname):
|
|
117
|
+
def read_file(fname, out=True, max_size=None):
|
|
114
118
|
"Read file content, converting notebooks to XML if needed"
|
|
115
119
|
fname = Path(fname)
|
|
116
|
-
if fname.suffix == '.ipynb':
|
|
117
|
-
|
|
120
|
+
if fname.suffix == '.ipynb': res = nb2xml(fname, out=out)
|
|
121
|
+
else: res = fname.read_text()
|
|
122
|
+
if max_size and len(res)>max_size: return f"[Skipped: {fname.name} exceeds {max_size} bytes]"
|
|
123
|
+
return res
|
|
118
124
|
|
|
119
125
|
# %% ../00_xml.ipynb
|
|
120
126
|
def files2ctx(
|
|
121
127
|
fnames:list[Union[str,Path]], # List of file names to add to context
|
|
122
|
-
prefix:bool=True # Include Anthropic's suggested prose intro?
|
|
128
|
+
prefix:bool=True, # Include Anthropic's suggested prose intro?
|
|
129
|
+
out:bool=True, # Include notebook cell outputs?
|
|
130
|
+
srcs:Optional[list]=None, # Use the labels instead of `fnames`
|
|
131
|
+
title:str=None, # Optional title attr for Documents element
|
|
132
|
+
max_size:int=None # Skip files larger than this (bytes)
|
|
123
133
|
)->str: # XML for LM context
|
|
124
134
|
"Convert files to XML context, handling notebooks"
|
|
125
135
|
fnames = [Path(o) for o in fnames]
|
|
126
|
-
contents = [read_file(o) for o in fnames]
|
|
127
|
-
return docs_xml(contents, fnames, prefix=prefix)
|
|
136
|
+
contents = [read_file(o, out=out, max_size=max_size) for o in fnames]
|
|
137
|
+
return docs_xml(contents, srcs or fnames, prefix=prefix, title=title)
|
|
128
138
|
|
|
129
139
|
# %% ../00_xml.ipynb
|
|
130
140
|
@delegates(globtastic)
|
|
131
141
|
def folder2ctx(
|
|
132
|
-
folder:Union[str,Path],
|
|
142
|
+
folder:Union[str,Path],
|
|
133
143
|
prefix:bool=True, # Include Anthropic's suggested prose intro?
|
|
134
|
-
|
|
135
|
-
|
|
144
|
+
out:bool=True, # Include notebook cell outputs?
|
|
145
|
+
include_base:bool=True, # Include full path in src?
|
|
146
|
+
title:str=None, # Optional title attr for Documents element
|
|
147
|
+
max_size:int=100_000, # Skip files larger than this (bytes)
|
|
148
|
+
**kwargs
|
|
149
|
+
)->str:
|
|
150
|
+
"Convert folder contents to XML context, handling notebooks"
|
|
151
|
+
folder = Path(folder)
|
|
136
152
|
fnames = globtastic(folder, **kwargs)
|
|
137
|
-
|
|
153
|
+
srcs = fnames if include_base else [Path(f).relative_to(folder) for f in fnames]
|
|
154
|
+
return files2ctx(fnames, prefix=prefix, out=out, srcs=srcs, title=title, max_size=max_size)
|
|
155
|
+
|
|
156
|
+
# %% ../00_xml.ipynb
|
|
157
|
+
@delegates(folder2ctx)
|
|
158
|
+
def repo2ctx(
|
|
159
|
+
owner:str, # GitHub repo owner
|
|
160
|
+
repo:str, # GitHub repo name
|
|
161
|
+
ref:str=None, # Git ref (branch/tag/sha); defaults to repo's default branch
|
|
162
|
+
**kwargs # Passed to `folder2ctx`
|
|
163
|
+
)->str: # XML for LM context
|
|
164
|
+
"Convert GitHub repo to XML context without cloning"
|
|
165
|
+
import tempfile, tarfile, io
|
|
166
|
+
api = GhApi()
|
|
167
|
+
if ref is None: ref = api.repos.get(owner, repo).default_branch
|
|
168
|
+
data = api.repos.download_tarball_archive(owner, repo, ref)
|
|
169
|
+
parts = ' | '.join(f"{k}: {', '.join(v) if isinstance(v, (list,tuple)) else v}"
|
|
170
|
+
for k,v in kwargs.items() if v)
|
|
171
|
+
title = f"GitHub repository contents from {owner}/{repo} at ref '{ref}'"
|
|
172
|
+
if parts: title += f" (filters applied: {parts})"
|
|
173
|
+
tf = tarfile.open(fileobj=io.BytesIO(data))
|
|
174
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
175
|
+
tf.extractall(tmp, filter='data')
|
|
176
|
+
subdir = Path(tmp) / tf.getmembers()[0].name.split('/')[0]
|
|
177
|
+
return folder2ctx(subdir, include_base=False, title=title, **kwargs)
|
|
138
178
|
|
|
139
179
|
# %% ../00_xml.ipynb
|
|
140
180
|
@call_parse
|
|
141
181
|
@delegates(folder2ctx)
|
|
142
182
|
def folder2ctx_cli(
|
|
143
183
|
folder:str, # Folder name containing files to add to context
|
|
184
|
+
out:bool=True, # Include notebook cell outputs?
|
|
144
185
|
**kwargs # Passed to `folder2ctx`
|
|
145
186
|
)->str: # XML for Claude context
|
|
146
|
-
|
|
187
|
+
"CLI to convert folder contents to XML context, handling notebooks"
|
|
188
|
+
print(folder2ctx(folder, out=out, **kwargs))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: toolslm
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
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>=1.
|
|
19
|
+
Requires-Dist: fastcore>=1.9.6
|
|
20
20
|
Requires-Dist: httpx
|
|
21
21
|
Provides-Extra: dev
|
|
22
22
|
Dynamic: author
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
toolslm/__init__.py,sha256=xmkmdvq15kb61xdtCoa1YARnvHBnUgI-0GWIJYvHNeA,22
|
|
2
|
+
toolslm/_modidx.py,sha256=kpgsDpj-Tvn90wezrHaMttyzhNcyNVgw_dQgK10qotI,5308
|
|
3
|
+
toolslm/download.py,sha256=g3BxUSxylC_575M7RFSJ1GI3Co3EwPDdEeWzxaf2Czk,4451
|
|
4
|
+
toolslm/funccall.py,sha256=0OBrx6KzI0KK13L-5Hn69yah9oZhgTsKchmMenCoT0A,10421
|
|
5
|
+
toolslm/md_hier.py,sha256=r_NPezhgfxjRmSYFlu_ND42hXt1qSbaPWHTcjbviOn4,11010
|
|
6
|
+
toolslm/shell.py,sha256=dGInuRKvexu21VmtZkw_0S3BGiTsbAongUG-yG4YHpc,1566
|
|
7
|
+
toolslm/xml.py,sha256=tAHoqXrTRiX8i3pR-9KpHoBb8QXJ_TKEVyTEOPviudE,8095
|
|
8
|
+
toolslm-0.3.9.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
+
toolslm-0.3.9.dist-info/METADATA,sha256=djSwIqYu8Taj8g0yyXKw3IqFr_fbAKhbI3aQu14kv9U,2403
|
|
10
|
+
toolslm-0.3.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
toolslm-0.3.9.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
|
|
12
|
+
toolslm-0.3.9.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
|
|
13
|
+
toolslm-0.3.9.dist-info/RECORD,,
|
toolslm-0.3.3.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
toolslm/__init__.py,sha256=8KcCYTXH99C2-gCLuPILJvtT9YftRWJsartIx6TQ2ZY,22
|
|
2
|
-
toolslm/_modidx.py,sha256=KeI16uj9ZfA5ZWlmov5ATQwf3291dayJ42Bp1dh69gU,4856
|
|
3
|
-
toolslm/download.py,sha256=g3BxUSxylC_575M7RFSJ1GI3Co3EwPDdEeWzxaf2Czk,4451
|
|
4
|
-
toolslm/funccall.py,sha256=PSmQ9kZsJvYh3egH7k1vQPYFn-XBm5E_CCKDVdX9tfg,8506
|
|
5
|
-
toolslm/md_hier.py,sha256=Havk9Hf0t2Xt67n_r7ZxCsS0pciR85iLcE5quShvkTg,10032
|
|
6
|
-
toolslm/shell.py,sha256=dGInuRKvexu21VmtZkw_0S3BGiTsbAongUG-yG4YHpc,1566
|
|
7
|
-
toolslm/xml.py,sha256=2QGVGrTWfyyf0duBDn_Of5kFzYFoBjvl8PrZKgNxbUU,5806
|
|
8
|
-
toolslm-0.3.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
-
toolslm-0.3.3.dist-info/METADATA,sha256=6jm9oNXtN4EDwj2OEbgtQg2pQ3vu24bV9VGN7oex2BU,2404
|
|
10
|
-
toolslm-0.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
-
toolslm-0.3.3.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
|
|
12
|
-
toolslm-0.3.3.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
|
|
13
|
-
toolslm-0.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|