toolslm 0.1.0__py3-none-any.whl → 0.1.2__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 +5 -1
- toolslm/download.py +9 -8
- toolslm/funccall.py +59 -21
- toolslm/md_hier.py +40 -1
- {toolslm-0.1.0.dist-info → toolslm-0.1.2.dist-info}/METADATA +16 -3
- toolslm-0.1.2.dist-info/RECORD +13 -0
- {toolslm-0.1.0.dist-info → toolslm-0.1.2.dist-info}/WHEEL +1 -1
- toolslm-0.1.0.dist-info/RECORD +0 -13
- {toolslm-0.1.0.dist-info → toolslm-0.1.2.dist-info}/entry_points.txt +0 -0
- {toolslm-0.1.0.dist-info → toolslm-0.1.2.dist-info/licenses}/LICENSE +0 -0
- {toolslm-0.1.0.dist-info → toolslm-0.1.2.dist-info}/top_level.txt +0 -0
toolslm/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.2"
|
toolslm/_modidx.py
CHANGED
|
@@ -14,15 +14,19 @@ 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.PathArg': ('funccall.html#patharg', 'toolslm/funccall.py'),
|
|
18
|
+
'toolslm.funccall._copy_loc': ('funccall.html#_copy_loc', 'toolslm/funccall.py'),
|
|
18
19
|
'toolslm.funccall._get_nested_schema': ('funccall.html#_get_nested_schema', 'toolslm/funccall.py'),
|
|
19
20
|
'toolslm.funccall._handle_container': ('funccall.html#_handle_container', 'toolslm/funccall.py'),
|
|
20
21
|
'toolslm.funccall._handle_type': ('funccall.html#_handle_type', 'toolslm/funccall.py'),
|
|
22
|
+
'toolslm.funccall._is_container': ('funccall.html#_is_container', 'toolslm/funccall.py'),
|
|
23
|
+
'toolslm.funccall._is_parameterized': ('funccall.html#_is_parameterized', 'toolslm/funccall.py'),
|
|
21
24
|
'toolslm.funccall._param': ('funccall.html#_param', 'toolslm/funccall.py'),
|
|
22
25
|
'toolslm.funccall._process_property': ('funccall.html#_process_property', 'toolslm/funccall.py'),
|
|
23
26
|
'toolslm.funccall._run': ('funccall.html#_run', 'toolslm/funccall.py'),
|
|
24
27
|
'toolslm.funccall._types': ('funccall.html#_types', 'toolslm/funccall.py'),
|
|
25
28
|
'toolslm.funccall.call_func': ('funccall.html#call_func', 'toolslm/funccall.py'),
|
|
29
|
+
'toolslm.funccall.call_func_async': ('funccall.html#call_func_async', 'toolslm/funccall.py'),
|
|
26
30
|
'toolslm.funccall.get_schema': ('funccall.html#get_schema', 'toolslm/funccall.py'),
|
|
27
31
|
'toolslm.funccall.mk_ns': ('funccall.html#mk_ns', 'toolslm/funccall.py'),
|
|
28
32
|
'toolslm.funccall.python': ('funccall.html#python', 'toolslm/funccall.py')},
|
toolslm/download.py
CHANGED
|
@@ -27,10 +27,10 @@ def read_md(url, rm_comments=True, rm_details=True, **kwargs):
|
|
|
27
27
|
return clean_md(get(url, **kwargs).text, rm_comments=rm_comments, rm_details=rm_details)
|
|
28
28
|
|
|
29
29
|
# %% ../03_download.ipynb 7
|
|
30
|
-
def html2md(s:str):
|
|
30
|
+
def html2md(s:str, ignore_links=True):
|
|
31
31
|
"Convert `s` from HTML to markdown"
|
|
32
32
|
o = HTML2Text(bodywidth=5000)
|
|
33
|
-
o.ignore_links =
|
|
33
|
+
o.ignore_links = ignore_links
|
|
34
34
|
o.mark_code = True
|
|
35
35
|
o.ignore_images = True
|
|
36
36
|
return o.handle(s)
|
|
@@ -42,6 +42,7 @@ def read_html(url, # URL to read
|
|
|
42
42
|
rm_details=True, # Removes `<details>` tags
|
|
43
43
|
multi=False, # Get all matches to `sel` or first one
|
|
44
44
|
wrap_tag=None, #If multi, each selection wrapped with <wrap_tag>content</wrap_tag>
|
|
45
|
+
ignore_links=True,
|
|
45
46
|
): # Cleaned markdown
|
|
46
47
|
"Get `url`, optionally selecting CSS selector `sel`, and convert to clean markdown"
|
|
47
48
|
page = get(url).text
|
|
@@ -51,12 +52,12 @@ def read_html(url, # URL to read
|
|
|
51
52
|
page = [str(el) for el in soup.select(sel)]
|
|
52
53
|
if not wrap_tag: page = "\n".join(page)
|
|
53
54
|
else: page = str(soup.select_one(sel))
|
|
54
|
-
mds = map(lambda x: clean_md(html2md(x), rm_comments, rm_details=rm_details), tuplify(page))
|
|
55
|
+
mds = map(lambda x: clean_md(html2md(x, ignore_links=ignore_links), rm_comments, rm_details=rm_details), tuplify(page))
|
|
55
56
|
if wrap_tag: return '\n'.join([f"\n<{wrap_tag}>\n{o}</{wrap_tag}>\n" for o in mds])
|
|
56
57
|
else: return'\n'.join(mds)
|
|
57
58
|
|
|
58
59
|
|
|
59
|
-
# %% ../03_download.ipynb
|
|
60
|
+
# %% ../03_download.ipynb 13
|
|
60
61
|
def get_llmstxt(url, optional=False, n_workers=None):
|
|
61
62
|
"Get llms.txt file from and expand it with `llms_txt.create_ctx()`"
|
|
62
63
|
if not url.endswith('llms.txt'): return None
|
|
@@ -64,7 +65,7 @@ def get_llmstxt(url, optional=False, n_workers=None):
|
|
|
64
65
|
if resp.status_code!=200: return None
|
|
65
66
|
return create_ctx(resp.text, optional=optional, n_workers=n_workers)
|
|
66
67
|
|
|
67
|
-
# %% ../03_download.ipynb
|
|
68
|
+
# %% ../03_download.ipynb 15
|
|
68
69
|
def split_url(url):
|
|
69
70
|
"Split `url` into base, path, and file name, normalising name to '/' if empty"
|
|
70
71
|
parsed = urlparse(url.strip('/'))
|
|
@@ -74,13 +75,13 @@ def split_url(url):
|
|
|
74
75
|
if not path and not fname: path='/'
|
|
75
76
|
return base,path,fname
|
|
76
77
|
|
|
77
|
-
# %% ../03_download.ipynb
|
|
78
|
+
# %% ../03_download.ipynb 17
|
|
78
79
|
def _tryget(url):
|
|
79
80
|
"Return response from `url` if `status_code!=404`, otherwise `None`"
|
|
80
81
|
res = get(url)
|
|
81
82
|
return None if res.status_code==404 else url
|
|
82
83
|
|
|
83
|
-
# %% ../03_download.ipynb
|
|
84
|
+
# %% ../03_download.ipynb 18
|
|
84
85
|
def find_docs(url):
|
|
85
86
|
"If available, return LLM-friendly llms.txt context or markdown file location from `url`"
|
|
86
87
|
base,path,fname = split_url(url)
|
|
@@ -100,7 +101,7 @@ def find_docs(url):
|
|
|
100
101
|
if parsed_url.path == '/' or not parsed_url.path: return None
|
|
101
102
|
return find_docs(urljoin(url, '..'))
|
|
102
103
|
|
|
103
|
-
# %% ../03_download.ipynb
|
|
104
|
+
# %% ../03_download.ipynb 23
|
|
104
105
|
def read_docs(url, optional=False, n_workers=None, rm_comments=True, rm_details=True):
|
|
105
106
|
"If available, return LLM-friendly llms.txt context or markdown file response for `url`"
|
|
106
107
|
url = find_docs(url)
|
toolslm/funccall.py
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../01_funccall.ipynb.
|
|
2
2
|
|
|
3
3
|
# %% auto 0
|
|
4
|
-
__all__ = ['empty', 'get_schema', 'python', 'mk_ns', 'call_func']
|
|
4
|
+
__all__ = ['empty', 'custom_types', 'get_schema', 'PathArg', 'python', 'mk_ns', 'call_func', 'call_func_async']
|
|
5
5
|
|
|
6
6
|
# %% ../01_funccall.ipynb 2
|
|
7
7
|
import inspect
|
|
8
8
|
from collections import abc
|
|
9
9
|
from fastcore.utils import *
|
|
10
10
|
from fastcore.docments import docments
|
|
11
|
+
from typing import get_origin, get_args, Dict, List, Optional, Tuple, Union
|
|
12
|
+
from types import UnionType
|
|
11
13
|
|
|
12
14
|
# %% ../01_funccall.ipynb 3
|
|
13
15
|
empty = inspect.Parameter.empty
|
|
@@ -18,11 +20,18 @@ def _types(t:type)->tuple[str,Optional[str]]:
|
|
|
18
20
|
if t is empty: raise TypeError('Missing type')
|
|
19
21
|
tmap = {int:"integer", float:"number", str:"string", bool:"boolean", list:"array", dict:"object"}
|
|
20
22
|
tmap.update({k.__name__: v for k, v in tmap.items()})
|
|
21
|
-
if getattr(t, '__origin__', None) in (list,tuple):
|
|
23
|
+
if getattr(t, '__origin__', None) in (list,tuple):
|
|
24
|
+
args = getattr(t, '__args__', None)
|
|
25
|
+
item_type = "object" if not args else tmap.get(t.__args__[0].__name__, "object")
|
|
26
|
+
return "array", item_type
|
|
27
|
+
# if t is a string like 'int', directly use the string as the key
|
|
22
28
|
elif isinstance(t, str): return tmap.get(t, "object"), None
|
|
29
|
+
# if t is the type itself and a container
|
|
30
|
+
elif get_origin(t): return tmap.get(get_origin(t).__name__, "object"), None
|
|
31
|
+
# if t is the type itself like int, use the __name__ representation as the key
|
|
23
32
|
else: return tmap.get(t.__name__, "object"), None
|
|
24
33
|
|
|
25
|
-
# %% ../01_funccall.ipynb
|
|
34
|
+
# %% ../01_funccall.ipynb 18
|
|
26
35
|
def _param(name, info):
|
|
27
36
|
"json schema parameter given `name` and `info` from docments full dict."
|
|
28
37
|
paramt,itemt = _types(info.anno)
|
|
@@ -31,17 +40,33 @@ def _param(name, info):
|
|
|
31
40
|
if info.default is not empty: pschema["default"] = info.default
|
|
32
41
|
return pschema
|
|
33
42
|
|
|
34
|
-
# %% ../01_funccall.ipynb
|
|
43
|
+
# %% ../01_funccall.ipynb 21
|
|
44
|
+
custom_types = {Path}
|
|
45
|
+
|
|
35
46
|
def _handle_type(t, defs):
|
|
36
47
|
"Handle a single type, creating nested schemas if necessary"
|
|
37
|
-
if
|
|
48
|
+
if t is NoneType: return {'type': 'null'}
|
|
49
|
+
if t in custom_types: return {'type':'string', 'format':t.__name__}
|
|
50
|
+
if isinstance(t, type) and not issubclass(t, (int, float, str, bool)) or inspect.isfunction(t):
|
|
38
51
|
defs[t.__name__] = _get_nested_schema(t)
|
|
39
52
|
return {'$ref': f'#/$defs/{t.__name__}'}
|
|
40
53
|
return {'type': _types(t)[0]}
|
|
41
54
|
|
|
42
|
-
# %% ../01_funccall.ipynb
|
|
55
|
+
# %% ../01_funccall.ipynb 23
|
|
56
|
+
def _is_container(t):
|
|
57
|
+
"Check if type is a container (list, dict, tuple, set, Union)"
|
|
58
|
+
origin = get_origin(t)
|
|
59
|
+
return origin in (list, dict, tuple, set, Union) if origin else False
|
|
60
|
+
|
|
61
|
+
def _is_parameterized(t):
|
|
62
|
+
"Check if type has arguments (e.g. list[int] vs list, dict[str, int] vs dict)"
|
|
63
|
+
return _is_container(t) and (get_args(t) != ())
|
|
64
|
+
|
|
65
|
+
# %% ../01_funccall.ipynb 29
|
|
43
66
|
def _handle_container(origin, args, defs):
|
|
44
|
-
"Handle container types like dict, list, tuple, set"
|
|
67
|
+
"Handle container types like dict, list, tuple, set, and Union"
|
|
68
|
+
if origin is Union or origin is UnionType:
|
|
69
|
+
return {"anyOf": [_handle_type(arg, defs) for arg in args]}
|
|
45
70
|
if origin is dict:
|
|
46
71
|
value_type = args[1].__args__[0] if hasattr(args[1], '__args__') else args[1]
|
|
47
72
|
return {
|
|
@@ -58,34 +83,35 @@ def _handle_container(origin, args, defs):
|
|
|
58
83
|
return schema
|
|
59
84
|
return None
|
|
60
85
|
|
|
61
|
-
# %% ../01_funccall.ipynb
|
|
86
|
+
# %% ../01_funccall.ipynb 30
|
|
62
87
|
def _process_property(name, obj, props, req, defs):
|
|
63
88
|
"Process a single property of the schema"
|
|
64
89
|
p = _param(name, obj)
|
|
65
90
|
props[name] = p
|
|
66
91
|
if obj.default is empty: req[name] = True
|
|
67
|
-
|
|
68
|
-
if
|
|
69
|
-
|
|
92
|
+
|
|
93
|
+
if _is_container(obj.anno) and _is_parameterized(obj.anno):
|
|
94
|
+
p.update(_handle_container(get_origin(obj.anno), get_args(obj.anno), defs))
|
|
70
95
|
else:
|
|
96
|
+
# Non-container type or container without arguments
|
|
71
97
|
p.update(_handle_type(obj.anno, defs))
|
|
72
98
|
|
|
73
|
-
# %% ../01_funccall.ipynb
|
|
99
|
+
# %% ../01_funccall.ipynb 31
|
|
74
100
|
def _get_nested_schema(obj):
|
|
75
101
|
"Generate nested JSON schema for a class or function"
|
|
76
102
|
d = docments(obj, full=True)
|
|
77
103
|
props, req, defs = {}, {}, {}
|
|
78
|
-
|
|
104
|
+
|
|
79
105
|
for n, o in d.items():
|
|
80
106
|
if n != 'return' and n != 'self':
|
|
81
107
|
_process_property(n, o, props, req, defs)
|
|
82
|
-
|
|
108
|
+
|
|
83
109
|
schema = dict(type='object', properties=props, title=obj.__name__ if isinstance(obj, type) else None)
|
|
84
110
|
if req: schema['required'] = list(req)
|
|
85
111
|
if defs: schema['$defs'] = defs
|
|
86
112
|
return schema
|
|
87
113
|
|
|
88
|
-
# %% ../01_funccall.ipynb
|
|
114
|
+
# %% ../01_funccall.ipynb 35
|
|
89
115
|
def get_schema(f:callable, pname='input_schema')->dict:
|
|
90
116
|
"Generate JSON schema for a class, function, or method"
|
|
91
117
|
schema = _get_nested_schema(f)
|
|
@@ -96,11 +122,16 @@ def get_schema(f:callable, pname='input_schema')->dict:
|
|
|
96
122
|
if ret.anno is not empty: desc += f'\n\nReturns:\n- type: {_types(ret.anno)[0]}'
|
|
97
123
|
return {"name": f.__name__, "description": desc, pname: schema}
|
|
98
124
|
|
|
99
|
-
# %% ../01_funccall.ipynb
|
|
125
|
+
# %% ../01_funccall.ipynb 46
|
|
126
|
+
def PathArg(
|
|
127
|
+
path: str # A filesystem path
|
|
128
|
+
): return Path(path)
|
|
129
|
+
|
|
130
|
+
# %% ../01_funccall.ipynb 66
|
|
100
131
|
import ast, time, signal, traceback
|
|
101
132
|
from fastcore.utils import *
|
|
102
133
|
|
|
103
|
-
# %% ../01_funccall.ipynb
|
|
134
|
+
# %% ../01_funccall.ipynb 67
|
|
104
135
|
def _copy_loc(new, orig):
|
|
105
136
|
"Copy location information from original node to new node and all children."
|
|
106
137
|
new = ast.copy_location(new, orig)
|
|
@@ -109,7 +140,7 @@ def _copy_loc(new, orig):
|
|
|
109
140
|
elif isinstance(o, list): setattr(new, field, [_copy_loc(value, orig) for value in o])
|
|
110
141
|
return new
|
|
111
142
|
|
|
112
|
-
# %% ../01_funccall.ipynb
|
|
143
|
+
# %% ../01_funccall.ipynb 69
|
|
113
144
|
def _run(code:str ):
|
|
114
145
|
"Run `code`, returning final expression (similar to IPython)"
|
|
115
146
|
tree = ast.parse(code)
|
|
@@ -132,7 +163,7 @@ def _run(code:str ):
|
|
|
132
163
|
if _result is not None: return _result
|
|
133
164
|
return stdout_buffer.getvalue().strip()
|
|
134
165
|
|
|
135
|
-
# %% ../01_funccall.ipynb
|
|
166
|
+
# %% ../01_funccall.ipynb 74
|
|
136
167
|
def python(code, # Code to execute
|
|
137
168
|
timeout=5 # Maximum run time in seconds before a `TimeoutError` is raised
|
|
138
169
|
): # Result of last node, if it's an expression, or `None` otherwise
|
|
@@ -145,7 +176,7 @@ def python(code, # Code to execute
|
|
|
145
176
|
except Exception as e: return traceback.format_exc()
|
|
146
177
|
finally: signal.alarm(0)
|
|
147
178
|
|
|
148
|
-
# %% ../01_funccall.ipynb
|
|
179
|
+
# %% ../01_funccall.ipynb 81
|
|
149
180
|
def mk_ns(*funcs_or_objs):
|
|
150
181
|
merged = {}
|
|
151
182
|
for o in funcs_or_objs:
|
|
@@ -154,9 +185,16 @@ def mk_ns(*funcs_or_objs):
|
|
|
154
185
|
if callable(o) and hasattr(o, '__name__'): merged |= {o.__name__: o}
|
|
155
186
|
return merged
|
|
156
187
|
|
|
157
|
-
# %% ../01_funccall.ipynb
|
|
188
|
+
# %% ../01_funccall.ipynb 90
|
|
158
189
|
def call_func(fc_name, fc_inputs, ns):
|
|
159
190
|
"Call the function `fc_name` with the given `fc_inputs` using namespace `ns`."
|
|
160
191
|
if not isinstance(ns, abc.Mapping): ns = mk_ns(*ns)
|
|
161
192
|
func = ns[fc_name]
|
|
162
193
|
return func(**fc_inputs)
|
|
194
|
+
|
|
195
|
+
# %% ../01_funccall.ipynb 97
|
|
196
|
+
async def call_func_async(fc_name, fc_inputs, ns):
|
|
197
|
+
"Awaits the function `fc_name` with the given `fc_inputs` using namespace `ns`."
|
|
198
|
+
if not isinstance(ns, abc.Mapping): ns = mk_ns(*ns)
|
|
199
|
+
func = ns[fc_name]
|
|
200
|
+
return await func(**fc_inputs)
|
toolslm/md_hier.py
CHANGED
|
@@ -7,9 +7,15 @@ def markdown_to_dict(markdown_content):
|
|
|
7
7
|
|
|
8
8
|
lines = markdown_content.splitlines()
|
|
9
9
|
headings = []
|
|
10
|
+
in_code_block = False
|
|
10
11
|
|
|
11
12
|
# Parse headings with their levels and line numbers
|
|
12
13
|
for idx, line in enumerate(lines):
|
|
14
|
+
# Toggle code block state when encountering fence
|
|
15
|
+
if line.strip().startswith('```'): in_code_block = not in_code_block
|
|
16
|
+
|
|
17
|
+
# Only detect headings when not in a code block
|
|
18
|
+
if in_code_block: continue
|
|
13
19
|
match = re.match(r'^(#{1,6})\s*(.*)', line)
|
|
14
20
|
if match:
|
|
15
21
|
level = len(match.group(1))
|
|
@@ -29,13 +35,15 @@ def markdown_to_dict(markdown_content):
|
|
|
29
35
|
|
|
30
36
|
# Build the dictionary with hierarchical keys
|
|
31
37
|
result,stack = {},[]
|
|
38
|
+
first_level = headings[0]['level']
|
|
32
39
|
for h in headings:
|
|
33
|
-
stack = stack[:h['level'] -
|
|
40
|
+
stack = stack[:h['level'] - first_level] + [clean_heading(h['text'])]
|
|
34
41
|
key = '.'.join(stack)
|
|
35
42
|
result[key] = h['content']
|
|
36
43
|
return dict2obj(result)
|
|
37
44
|
|
|
38
45
|
def create_heading_dict(text):
|
|
46
|
+
text = re.sub(r'```[\s\S]*?```', '', text)
|
|
39
47
|
headings = re.findall(r'^#+.*', text, flags=re.MULTILINE)
|
|
40
48
|
result = {}
|
|
41
49
|
stack = [result]
|
|
@@ -126,11 +134,42 @@ Admin users management.
|
|
|
126
134
|
assert result['Parent.Child'] == '## Child\nChild content.\n### Grandchild\nGrandchild content.'
|
|
127
135
|
assert result['Parent.Child.Grandchild'] == '### Grandchild\nGrandchild content.'
|
|
128
136
|
|
|
137
|
+
def test_multiple_level2_siblings():
|
|
138
|
+
md_content = "##Sib 1\n##Sib 2\n##Sib 3\n##Sib 4\n##Sib 5'"
|
|
139
|
+
result = markdown_to_dict(md_content)
|
|
140
|
+
assert 'Sib 1' in result
|
|
141
|
+
assert 'Sib 2' in result
|
|
142
|
+
assert 'Sib 3' in result
|
|
143
|
+
assert 'Sib 4' in result
|
|
144
|
+
assert 'Sib 5' in result
|
|
145
|
+
|
|
146
|
+
def test_code_chunks_escaped():
|
|
147
|
+
md_content = "# Parent\nParent content.\n## Child\nChild content.\n```python\n# Code comment\nprint('Hello, world!')\n```"
|
|
148
|
+
result = markdown_to_dict(md_content)
|
|
149
|
+
assert 'Code comment' not in result
|
|
150
|
+
assert "# Code comment" in result['Parent.Child']
|
|
151
|
+
|
|
129
152
|
test_empty_content()
|
|
130
153
|
test_special_characters()
|
|
131
154
|
test_duplicate_headings()
|
|
132
155
|
test_no_content()
|
|
133
156
|
test_different_levels()
|
|
134
157
|
test_parent_includes_subheadings()
|
|
158
|
+
test_multiple_level2_siblings()
|
|
159
|
+
test_code_chunks_escaped()
|
|
135
160
|
print('tests passed')
|
|
136
161
|
|
|
162
|
+
def test_nested_headings():
|
|
163
|
+
md_content = "# Parent\nParent content.\n## Child\nChild content.\n### Grandchild\nGrandchild content."
|
|
164
|
+
result = create_heading_dict(md_content)
|
|
165
|
+
assert 'Child' in result['Parent']
|
|
166
|
+
assert 'Grandchild' in result['Parent']['Child']
|
|
167
|
+
|
|
168
|
+
def test_code_chunks_escaped():
|
|
169
|
+
md_content = "# Parent\nParent content.\n## Child\nChild content.\n```python\n# Code comment\nprint('Hello, world!')\n```"
|
|
170
|
+
result = create_heading_dict(md_content)
|
|
171
|
+
assert 'Code comment' not in result
|
|
172
|
+
|
|
173
|
+
test_nested_headings()
|
|
174
|
+
test_code_chunks_escaped()
|
|
175
|
+
print('tests passed')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: toolslm
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
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
|
|
@@ -20,8 +20,21 @@ Requires-Dist: fastcore>=1.5.47
|
|
|
20
20
|
Requires-Dist: beautifulsoup4
|
|
21
21
|
Requires-Dist: html2text
|
|
22
22
|
Requires-Dist: httpx
|
|
23
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: llms_txt
|
|
24
24
|
Provides-Extra: dev
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: keywords
|
|
32
|
+
Dynamic: license
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
Dynamic: provides-extra
|
|
35
|
+
Dynamic: requires-dist
|
|
36
|
+
Dynamic: requires-python
|
|
37
|
+
Dynamic: summary
|
|
25
38
|
|
|
26
39
|
# toolslm
|
|
27
40
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
toolslm/__init__.py,sha256=YvuYzWnKtqBb-IqG8HAu-nhIYAsgj9Vmc_b9o7vO-js,22
|
|
2
|
+
toolslm/_modidx.py,sha256=-D-B5o30VGs11gBKf96lpADVXnZhdiVEshJpLzmUnDs,4378
|
|
3
|
+
toolslm/download.py,sha256=d84O8PCX7uAbLg0HTbNNfCdANPcnhXFu4qzOtcfJfHU,4465
|
|
4
|
+
toolslm/funccall.py,sha256=yAZmu2gIRtND-5pOuLCp7P4dor0FV_xntcacnZ81j0M,8210
|
|
5
|
+
toolslm/md_hier.py,sha256=4uC12443tPBduYJgIZZIcEat2VG0x7JYC8-SwDdS2JY,6360
|
|
6
|
+
toolslm/shell.py,sha256=GVqfL74NHw66zzZ7jvGVLjE55ZNJGBPvEb8kLz4aoYc,1576
|
|
7
|
+
toolslm/xml.py,sha256=QNwUavoMkFK84D7dMwnBjqlYJwN-pJ7u3BxOeDuNAmk,4088
|
|
8
|
+
toolslm-0.1.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
+
toolslm-0.1.2.dist-info/METADATA,sha256=gGurWuj5SWNPQvCPKbd8oc5Iz9x4NPxv8bx_C8w3Kps,2483
|
|
10
|
+
toolslm-0.1.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
11
|
+
toolslm-0.1.2.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
|
|
12
|
+
toolslm-0.1.2.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
|
|
13
|
+
toolslm-0.1.2.dist-info/RECORD,,
|
toolslm-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
toolslm/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
|
|
2
|
-
toolslm/_modidx.py,sha256=EIl2FBWhcZUS46r1AU0wURYg2O6Z3aXTPUr3p8Smrqk,3882
|
|
3
|
-
toolslm/download.py,sha256=tXhq77GCqwVFDzTtzjcSAjxUWRiyPsjlXzkMjleH3dQ,4378
|
|
4
|
-
toolslm/funccall.py,sha256=hSvBvfMv-YcBSUUs4-NrYu1f8jg4gfu2s82cPyIHVkU,6534
|
|
5
|
-
toolslm/md_hier.py,sha256=hkCjuOfIFWuMEiM2_XCoD9QIBjy9huLOSvpX_bMdn0Y,4645
|
|
6
|
-
toolslm/shell.py,sha256=GVqfL74NHw66zzZ7jvGVLjE55ZNJGBPvEb8kLz4aoYc,1576
|
|
7
|
-
toolslm/xml.py,sha256=QNwUavoMkFK84D7dMwnBjqlYJwN-pJ7u3BxOeDuNAmk,4088
|
|
8
|
-
toolslm-0.1.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
-
toolslm-0.1.0.dist-info/METADATA,sha256=tQBydygSCJdH_wQaIbzC8Z8rZanQTJOdmpe1nEETkdE,2205
|
|
10
|
-
toolslm-0.1.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
11
|
-
toolslm-0.1.0.dist-info/entry_points.txt,sha256=xFz0Eymlo5X7BGpaO6DI9gMxvN5A7faebzrlr8ctp5I,95
|
|
12
|
-
toolslm-0.1.0.dist-info/top_level.txt,sha256=4hRTrFWayz_Kz5221XjvlpCwVFrW3WPi1P0fllkTq9s,8
|
|
13
|
-
toolslm-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|