fmtr.tools 1.1.1__py3-none-any.whl → 1.3.81__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.
- fmtr/tools/__init__.py +68 -52
- fmtr/tools/ai_tools/__init__.py +2 -2
- fmtr/tools/ai_tools/agentic_tools.py +151 -32
- fmtr/tools/ai_tools/inference_tools.py +2 -1
- fmtr/tools/api_tools.py +8 -5
- fmtr/tools/caching_tools.py +101 -3
- fmtr/tools/constants.py +33 -0
- fmtr/tools/context_tools.py +23 -0
- fmtr/tools/data_modelling_tools.py +227 -14
- fmtr/tools/database_tools/__init__.py +6 -0
- fmtr/tools/database_tools/document.py +51 -0
- fmtr/tools/datatype_tools.py +21 -1
- fmtr/tools/datetime_tools.py +12 -0
- fmtr/tools/debugging_tools.py +60 -0
- fmtr/tools/dns_tools/__init__.py +7 -0
- fmtr/tools/dns_tools/client.py +97 -0
- fmtr/tools/dns_tools/dm.py +257 -0
- fmtr/tools/dns_tools/proxy.py +66 -0
- fmtr/tools/dns_tools/server.py +138 -0
- fmtr/tools/docker_tools/__init__.py +6 -0
- fmtr/tools/entrypoints/__init__.py +0 -0
- fmtr/tools/entrypoints/cache_hfh.py +3 -0
- fmtr/tools/entrypoints/ep_test.py +2 -0
- fmtr/tools/entrypoints/install_yamlscript.py +8 -0
- fmtr/tools/{console_script_tools.py → entrypoints/remote_debug_test.py} +1 -6
- fmtr/tools/entrypoints/shell_debug.py +8 -0
- fmtr/tools/environment_tools.py +2 -2
- fmtr/tools/function_tools.py +77 -1
- fmtr/tools/google_api_tools.py +15 -4
- fmtr/tools/http_tools.py +26 -0
- fmtr/tools/inherit_tools.py +27 -0
- fmtr/tools/interface_tools/__init__.py +8 -0
- fmtr/tools/interface_tools/context.py +13 -0
- fmtr/tools/interface_tools/controls.py +354 -0
- fmtr/tools/interface_tools/interface_tools.py +189 -0
- fmtr/tools/iterator_tools.py +29 -0
- fmtr/tools/logging_tools.py +43 -16
- fmtr/tools/packaging_tools.py +14 -0
- fmtr/tools/path_tools/__init__.py +12 -0
- fmtr/tools/path_tools/app_path_tools.py +40 -0
- fmtr/tools/{path_tools.py → path_tools/path_tools.py} +156 -12
- fmtr/tools/path_tools/type_path_tools.py +3 -0
- fmtr/tools/pattern_tools.py +260 -0
- fmtr/tools/pdf_tools.py +39 -1
- fmtr/tools/settings_tools.py +23 -4
- fmtr/tools/setup_tools/__init__.py +8 -0
- fmtr/tools/setup_tools/setup_tools.py +447 -0
- fmtr/tools/string_tools.py +92 -13
- fmtr/tools/tabular_tools.py +61 -0
- fmtr/tools/tools.py +27 -2
- fmtr/tools/version +1 -1
- fmtr/tools/version_tools/__init__.py +12 -0
- fmtr/tools/version_tools/version_tools.py +51 -0
- fmtr/tools/webhook_tools.py +17 -0
- fmtr/tools/yaml_tools.py +66 -5
- {fmtr_tools-1.1.1.dist-info → fmtr_tools-1.3.81.dist-info}/METADATA +136 -54
- fmtr_tools-1.3.81.dist-info/RECORD +93 -0
- {fmtr_tools-1.1.1.dist-info → fmtr_tools-1.3.81.dist-info}/WHEEL +1 -1
- fmtr_tools-1.3.81.dist-info/entry_points.txt +6 -0
- fmtr_tools-1.3.81.dist-info/top_level.txt +1 -0
- fmtr/tools/docker_tools.py +0 -30
- fmtr/tools/interface_tools.py +0 -64
- fmtr/tools/version_tools.py +0 -62
- fmtr_tools-1.1.1.dist-info/RECORD +0 -65
- fmtr_tools-1.1.1.dist-info/entry_points.txt +0 -3
- fmtr_tools-1.1.1.dist-info/top_level.txt +0 -2
- {fmtr_tools-1.1.1.dist-info → fmtr_tools-1.3.81.dist-info}/licenses/LICENSE +0 -0
fmtr/tools/__init__.py
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
__version__ = version.read()
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import fmtr.tools.async_tools as asyncio
|
|
2
|
+
import fmtr.tools.database_tools as db
|
|
6
3
|
import fmtr.tools.dataclass_tools as dataclass
|
|
7
4
|
import fmtr.tools.datatype_tools as datatype
|
|
8
5
|
import fmtr.tools.environment_tools as env
|
|
@@ -10,156 +7,175 @@ import fmtr.tools.environment_tools as environment
|
|
|
10
7
|
import fmtr.tools.function_tools as function
|
|
11
8
|
import fmtr.tools.hash_tools as hash
|
|
12
9
|
import fmtr.tools.import_tools as import_
|
|
10
|
+
import fmtr.tools.inherit_tools as inherit
|
|
13
11
|
import fmtr.tools.iterator_tools as iterator
|
|
14
12
|
import fmtr.tools.json_tools as json
|
|
13
|
+
import fmtr.tools.logging_tools as logging
|
|
14
|
+
import fmtr.tools.name_tools as name
|
|
15
|
+
import fmtr.tools.packaging_tools as packaging
|
|
15
16
|
import fmtr.tools.path_tools as path
|
|
16
17
|
import fmtr.tools.platform_tools as platform
|
|
17
18
|
import fmtr.tools.random_tools as random
|
|
19
|
+
import fmtr.tools.setup_tools as setup
|
|
18
20
|
import fmtr.tools.string_tools as string
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
from fmtr.tools
|
|
23
|
-
|
|
24
|
-
from fmtr.tools
|
|
25
|
-
from fmtr.tools.path_tools import Path, PackagePaths
|
|
21
|
+
from fmtr.tools import ai_tools as ai
|
|
22
|
+
from fmtr.tools import datetime_tools as dt
|
|
23
|
+
from fmtr.tools import dns_tools as dns
|
|
24
|
+
from fmtr.tools import docker_tools as docker
|
|
25
|
+
from fmtr.tools import interface_tools as interface
|
|
26
|
+
from fmtr.tools import version_tools as version
|
|
26
27
|
from fmtr.tools.constants import Constants
|
|
28
|
+
from fmtr.tools.import_tools import MissingExtraMockModule
|
|
29
|
+
from fmtr.tools.logging_tools import logger
|
|
30
|
+
# Submodules
|
|
31
|
+
from fmtr.tools.path_tools import Path, PackagePaths, AppPaths
|
|
32
|
+
from fmtr.tools.setup_tools import Setup, SetupPaths, Dependencies, Tools
|
|
27
33
|
|
|
28
34
|
try:
|
|
29
35
|
from fmtr.tools import augmentation_tools as augmentation
|
|
30
|
-
except
|
|
36
|
+
except ModuleNotFoundError as exception:
|
|
31
37
|
augmentation = MissingExtraMockModule('augmentation', exception)
|
|
32
38
|
|
|
33
39
|
try:
|
|
34
40
|
from fmtr.tools import yaml_tools as yaml
|
|
35
|
-
except
|
|
41
|
+
except ModuleNotFoundError as exception:
|
|
36
42
|
yaml = MissingExtraMockModule('yaml', exception)
|
|
37
43
|
|
|
38
|
-
try:
|
|
39
|
-
from fmtr.tools import docker_tools as docker
|
|
40
|
-
from fmtr.tools.docker_tools import Container
|
|
41
|
-
except ImportError as exception:
|
|
42
|
-
docker = Container = MissingExtraMockModule('docker.api', exception)
|
|
43
44
|
|
|
44
45
|
try:
|
|
45
46
|
from fmtr.tools import parallel_tools as parallel
|
|
46
|
-
except
|
|
47
|
+
except ModuleNotFoundError as exception:
|
|
47
48
|
parallel = MissingExtraMockModule('parallel', exception)
|
|
48
49
|
|
|
49
50
|
try:
|
|
50
51
|
from fmtr.tools import profiling_tools as profiling
|
|
51
52
|
from fmtr.tools.profiling_tools import Timer
|
|
52
|
-
except
|
|
53
|
+
except ModuleNotFoundError as exception:
|
|
53
54
|
profiling = Timer = MissingExtraMockModule('profiling', exception)
|
|
54
55
|
|
|
55
56
|
try:
|
|
56
57
|
import fmtr.tools.process_tools as process
|
|
57
58
|
from fmtr.tools.process_tools import ContextProcess
|
|
58
|
-
except
|
|
59
|
+
except ModuleNotFoundError as exception:
|
|
59
60
|
process = ContextProcess = MissingExtraMockModule('process', exception)
|
|
60
61
|
|
|
61
62
|
try:
|
|
62
63
|
from fmtr.tools import tokenization_tools as tokenization
|
|
63
|
-
except
|
|
64
|
+
except ModuleNotFoundError as exception:
|
|
64
65
|
tokenization = MissingExtraMockModule('tokenization', exception)
|
|
65
66
|
|
|
66
67
|
try:
|
|
67
68
|
from fmtr.tools import unicode_tools as unicode
|
|
68
|
-
except
|
|
69
|
+
except ModuleNotFoundError as exception:
|
|
69
70
|
unicode = MissingExtraMockModule('unicode', exception)
|
|
70
71
|
|
|
71
72
|
try:
|
|
72
73
|
from fmtr.tools import netrc_tools as netrc
|
|
73
|
-
except
|
|
74
|
+
except ModuleNotFoundError as exception:
|
|
74
75
|
netrc = MissingExtraMockModule('netrc', exception)
|
|
75
76
|
|
|
76
77
|
try:
|
|
77
78
|
from fmtr.tools import spaces_tools as spaces
|
|
78
|
-
except
|
|
79
|
+
except ModuleNotFoundError as exception:
|
|
79
80
|
spaces = MissingExtraMockModule('spaces', exception)
|
|
80
81
|
|
|
81
82
|
try:
|
|
82
83
|
from fmtr.tools import hfh_tools as hfh
|
|
83
|
-
except
|
|
84
|
+
except ModuleNotFoundError as exception:
|
|
84
85
|
hfh = MissingExtraMockModule('hfh', exception)
|
|
85
86
|
|
|
86
87
|
try:
|
|
87
88
|
from fmtr.tools import merging_tools as merging
|
|
88
89
|
from fmtr.tools.merging_tools import merge
|
|
89
|
-
except
|
|
90
|
+
except ModuleNotFoundError as exception:
|
|
90
91
|
merging = merge = MissingExtraMockModule('merging', exception)
|
|
91
92
|
|
|
92
93
|
try:
|
|
93
94
|
from fmtr.tools import api_tools as api
|
|
94
|
-
except
|
|
95
|
+
except ModuleNotFoundError as exception:
|
|
95
96
|
api = MissingExtraMockModule('api', exception)
|
|
96
97
|
|
|
97
|
-
try:
|
|
98
|
-
from fmtr.tools import ai_tools as ai
|
|
99
|
-
except ImportError as exception:
|
|
100
|
-
ai = MissingExtraMockModule('ai', exception)
|
|
101
|
-
|
|
102
98
|
try:
|
|
103
99
|
from fmtr.tools import data_modelling_tools as dm
|
|
104
|
-
except
|
|
100
|
+
except ModuleNotFoundError as exception:
|
|
105
101
|
dm = MissingExtraMockModule('dm', exception)
|
|
106
102
|
|
|
107
103
|
try:
|
|
108
104
|
from fmtr.tools import json_fix_tools as json_fix
|
|
109
|
-
except
|
|
105
|
+
except ModuleNotFoundError as exception:
|
|
110
106
|
json_fix = MissingExtraMockModule('json_fix', exception)
|
|
111
107
|
|
|
112
108
|
try:
|
|
113
109
|
from fmtr.tools import semantic_tools as semantic
|
|
114
|
-
except
|
|
110
|
+
except ModuleNotFoundError as exception:
|
|
115
111
|
semantic = MissingExtraMockModule('semantic', exception)
|
|
116
112
|
|
|
117
113
|
try:
|
|
118
114
|
from fmtr.tools import metric_tools as metric
|
|
119
|
-
except
|
|
115
|
+
except ModuleNotFoundError as exception:
|
|
120
116
|
metric = MissingExtraMockModule('metric', exception)
|
|
121
117
|
|
|
122
118
|
try:
|
|
123
119
|
from fmtr.tools import html_tools as html
|
|
124
|
-
except
|
|
120
|
+
except ModuleNotFoundError as exception:
|
|
125
121
|
html = MissingExtraMockModule('html', exception)
|
|
126
122
|
|
|
127
|
-
try:
|
|
128
|
-
from fmtr.tools import interface_tools as interface
|
|
129
|
-
except ImportError as exception:
|
|
130
|
-
interface = MissingExtraMockModule('interface', exception)
|
|
131
|
-
|
|
132
123
|
try:
|
|
133
124
|
from fmtr.tools import openai_tools as openai
|
|
134
|
-
except
|
|
125
|
+
except ModuleNotFoundError as exception:
|
|
135
126
|
openai = MissingExtraMockModule('openai', exception)
|
|
136
127
|
|
|
137
128
|
try:
|
|
138
129
|
from fmtr.tools import google_api_tools as google_api
|
|
139
|
-
except
|
|
130
|
+
except ModuleNotFoundError as exception:
|
|
140
131
|
google_api = MissingExtraMockModule('google.api', exception)
|
|
141
132
|
|
|
142
133
|
try:
|
|
143
134
|
from fmtr.tools import caching_tools as caching
|
|
144
|
-
except
|
|
135
|
+
except ModuleNotFoundError as exception:
|
|
145
136
|
caching = MissingExtraMockModule('caching', exception)
|
|
146
137
|
|
|
147
138
|
try:
|
|
148
139
|
from fmtr.tools import pdf_tools as pdf
|
|
149
|
-
except
|
|
140
|
+
except ModuleNotFoundError as exception:
|
|
150
141
|
pdf = MissingExtraMockModule('pdf', exception)
|
|
151
142
|
|
|
152
143
|
try:
|
|
153
144
|
from fmtr.tools import tabular_tools as tabular
|
|
154
|
-
except
|
|
145
|
+
except ModuleNotFoundError as exception:
|
|
155
146
|
tabular = MissingExtraMockModule('tabular', exception)
|
|
156
147
|
|
|
157
148
|
try:
|
|
158
149
|
from fmtr.tools import debugging_tools as debug
|
|
159
|
-
except
|
|
150
|
+
except ModuleNotFoundError as exception:
|
|
160
151
|
debug = MissingExtraMockModule('debug', exception)
|
|
161
152
|
|
|
162
153
|
try:
|
|
163
154
|
from fmtr.tools import settings_tools as sets
|
|
164
|
-
except
|
|
165
|
-
sets = MissingExtraMockModule('sets', exception)
|
|
155
|
+
except ModuleNotFoundError as exception:
|
|
156
|
+
sets = MissingExtraMockModule('sets', exception)
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
from fmtr.tools import pattern_tools as patterns
|
|
160
|
+
except ModuleNotFoundError as exception:
|
|
161
|
+
patterns = MissingExtraMockModule('patterns', exception)
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
from fmtr.tools import http_tools as http
|
|
165
|
+
from fmtr.tools.http_tools import Client
|
|
166
|
+
except ModuleNotFoundError as exception:
|
|
167
|
+
http = Client = MissingExtraMockModule('http', exception)
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
from fmtr.tools import webhook_tools as webhook
|
|
171
|
+
except ModuleNotFoundError as exception:
|
|
172
|
+
webhook = MissingExtraMockModule('webhook', exception)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def get_version():
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
Defer reading version
|
|
179
|
+
|
|
180
|
+
"""
|
|
181
|
+
return version.read()
|
fmtr/tools/ai_tools/__init__.py
CHANGED
|
@@ -2,10 +2,10 @@ from fmtr.tools.import_tools import MissingExtraMockModule
|
|
|
2
2
|
|
|
3
3
|
try:
|
|
4
4
|
from fmtr.tools.ai_tools import inference_tools as infer
|
|
5
|
-
except
|
|
5
|
+
except ModuleNotFoundError as exception:
|
|
6
6
|
infer = MissingExtraMockModule('ai', exception)
|
|
7
7
|
|
|
8
8
|
try:
|
|
9
9
|
from fmtr.tools.ai_tools import agentic_tools as agentic
|
|
10
|
-
except
|
|
10
|
+
except ModuleNotFoundError as exception:
|
|
11
11
|
agentic = MissingExtraMockModule('ai.client', exception)
|
|
@@ -1,33 +1,57 @@
|
|
|
1
|
+
from typing import List, Optional, Any, Annotated, Generic
|
|
2
|
+
|
|
1
3
|
import pydantic_ai
|
|
2
|
-
from
|
|
4
|
+
from pydantic import PlainValidator
|
|
5
|
+
from pydantic_ai import RunContext, ModelRetry
|
|
6
|
+
from pydantic_ai._output import OutputDataT
|
|
3
7
|
from pydantic_ai.agent import AgentRunResult, Agent
|
|
4
|
-
from pydantic_ai.messages import ModelRequest, RetryPromptPart
|
|
5
8
|
from pydantic_ai.models.openai import OpenAIModel
|
|
9
|
+
from pydantic_ai.output import OutputSpec, NativeOutput, ToolOutput
|
|
6
10
|
from pydantic_ai.providers.openai import OpenAIProvider
|
|
11
|
+
from pydantic_ai.tools import AgentDepsT
|
|
7
12
|
|
|
8
13
|
from fmtr.tools import environment_tools as env
|
|
9
14
|
from fmtr.tools.constants import Constants
|
|
15
|
+
from fmtr.tools.logging_tools import logger
|
|
16
|
+
from fmtr.tools.string_tools import truncate_mid
|
|
10
17
|
|
|
11
18
|
pydantic_ai.Agent.instrument_all()
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
|
|
21
|
+
class Validator:
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
Subclassable validator
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
async def validate(self, ctx: RunContext[Any], output: Any) -> List[str]:
|
|
29
|
+
raise NotImplementedError()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
api_key = env.get(Constants.FMTR_OPENAI_API_KEY_KEY, None)
|
|
33
|
+
|
|
34
|
+
class Task(Generic[AgentDepsT, OutputDataT]):
|
|
14
35
|
"""
|
|
15
36
|
|
|
16
37
|
Linear task definition, as Agent configuration and typing, plus state history.
|
|
17
38
|
|
|
18
39
|
"""
|
|
19
40
|
|
|
20
|
-
|
|
41
|
+
TypeDeps = str
|
|
42
|
+
TypeOutput = str
|
|
43
|
+
|
|
44
|
+
PROVIDER = OpenAIProvider(api_key=api_key) if api_key else None
|
|
21
45
|
|
|
22
46
|
API_HOST_FMTR = env.get(Constants.FMTR_AI_HOST_KEY, Constants.FMTR_AI_HOST_DEFAULT)
|
|
23
47
|
API_URL_FMTR = f'https://{API_HOST_FMTR}/v1'
|
|
24
48
|
PROVIDER_FMTR = OpenAIProvider(base_url=API_URL_FMTR)
|
|
25
49
|
|
|
26
50
|
MODEL_ID = 'gpt-4o'
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
RESULT_TYPE = str
|
|
51
|
+
MODEL_ID_FMTR = 'qwen2.5-coder:32b'
|
|
52
|
+
SYSTEM_PROMPT_STATIC = None
|
|
30
53
|
RESULT_RETRIES = 5
|
|
54
|
+
VALIDATORS: List[Validator] = []
|
|
31
55
|
|
|
32
56
|
def __init__(self, *args, **kwargs):
|
|
33
57
|
"""
|
|
@@ -37,64 +61,159 @@ class Task:
|
|
|
37
61
|
"""
|
|
38
62
|
|
|
39
63
|
self.model = OpenAIModel(self.MODEL_ID, provider=self.PROVIDER)
|
|
40
|
-
self.agent = Agent(
|
|
64
|
+
self.agent = Agent[AgentDepsT, OutputDataT](
|
|
41
65
|
*args,
|
|
42
66
|
model=self.model,
|
|
43
|
-
system_prompt=self.
|
|
44
|
-
deps_type=self.
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
system_prompt=self.SYSTEM_PROMPT_STATIC or [],
|
|
68
|
+
deps_type=self.TypeDeps,
|
|
69
|
+
output_type=self.tool_output,
|
|
70
|
+
output_retries=self.RESULT_RETRIES,
|
|
47
71
|
**kwargs
|
|
48
72
|
)
|
|
49
73
|
|
|
50
74
|
self.agent.output_validator(self.validate)
|
|
75
|
+
self.agent.system_prompt(self.add_system_prompt)
|
|
51
76
|
self.history = []
|
|
52
77
|
|
|
53
|
-
|
|
78
|
+
@property
|
|
79
|
+
def tool_output(self) -> OutputSpec[OutputDataT]:
|
|
54
80
|
"""
|
|
55
81
|
|
|
56
|
-
|
|
82
|
+
Tool output specification (e.g. ToolOutput/NativeOutput etc.)
|
|
57
83
|
|
|
58
84
|
"""
|
|
85
|
+
return ToolOutput(self.TypeOutput)
|
|
59
86
|
|
|
60
|
-
result = await self.agent.run(*args, message_history=self.history, **kwargs)
|
|
61
|
-
self.history = result.all_messages()
|
|
62
|
-
return result
|
|
63
87
|
|
|
64
|
-
|
|
88
|
+
@property
|
|
89
|
+
def sync_runner(self):
|
|
65
90
|
"""
|
|
66
91
|
|
|
67
|
-
|
|
92
|
+
Convenience/debug function to run without async.
|
|
68
93
|
|
|
69
94
|
"""
|
|
70
|
-
|
|
71
|
-
|
|
95
|
+
import asyncio
|
|
96
|
+
return asyncio.run
|
|
72
97
|
|
|
73
|
-
|
|
74
|
-
|
|
98
|
+
async def run(self, *args, deps=None, **kwargs) -> AgentRunResult[OutputDataT]:
|
|
99
|
+
"""
|
|
75
100
|
|
|
76
|
-
|
|
101
|
+
Run Agent with deps-relative user prompt and while storing history
|
|
77
102
|
|
|
78
|
-
|
|
103
|
+
"""
|
|
104
|
+
result = await self.agent.run(*args, user_prompt=self.get_prompt(deps), deps=deps, message_history=self.history, **kwargs)
|
|
105
|
+
self.history = result.all_messages()
|
|
79
106
|
return result
|
|
80
107
|
|
|
81
|
-
async def validate(self, ctx: RunContext[
|
|
108
|
+
async def validate(self, ctx: RunContext[AgentDepsT], output: OutputDataT) -> OutputDataT:
|
|
82
109
|
"""
|
|
83
110
|
|
|
84
|
-
|
|
111
|
+
Aggregate any validation failures and combine them into a single ModelRetry exception
|
|
85
112
|
|
|
86
113
|
"""
|
|
114
|
+
msgs = []
|
|
115
|
+
for validator in self.VALIDATORS:
|
|
116
|
+
msgs += validator.validate(ctx, output)
|
|
117
|
+
|
|
118
|
+
if msgs:
|
|
119
|
+
msg = '. '.join(msgs)
|
|
120
|
+
logger.warning(msg)
|
|
121
|
+
raise ModelRetry(msg)
|
|
122
|
+
|
|
87
123
|
return output
|
|
88
124
|
|
|
125
|
+
def get_prompt(self, deps: Optional[AgentDepsT]) -> Optional[str]:
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
Dummy prompt generator
|
|
89
129
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
130
|
+
"""
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
def add_system_prompt(self, ctx: RunContext[AgentDepsT]) -> str | List[str]:
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
Dummy system prompt append
|
|
137
|
+
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
return []
|
|
141
|
+
|
|
142
|
+
def reset(self):
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
Reset the task by deleting its history.
|
|
146
|
+
|
|
147
|
+
"""
|
|
148
|
+
self.history = []
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def tool_schema(self):
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
Impossible to find otherwise.
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
return self.agent._output_toolset
|
|
158
|
+
|
|
159
|
+
def __repr__(self):
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
String representation of the object
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
return f'{self.__class__.__name__}({repr(truncate_mid(self.SYSTEM_PROMPT_STATIC, 100))})'
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def default_prompt_none_specified(text):
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
If the prompt is falsey, explicitly state None Specified
|
|
172
|
+
|
|
173
|
+
"""
|
|
174
|
+
if not (text or '').strip():
|
|
175
|
+
return Constants.PROMPT_NONE_SPECIFIED
|
|
176
|
+
return text
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
StringDefaultNoneSpecified = Annotated[Optional[str], PlainValidator(default_prompt_none_specified)]
|
|
93
180
|
|
|
94
181
|
|
|
95
182
|
if __name__ == '__main__':
|
|
96
183
|
import asyncio
|
|
184
|
+
from fmtr.tools import dm
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class TestOutput(dm.Base):
|
|
188
|
+
text: str
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class TestDeps(dm.Base):
|
|
192
|
+
lang: str
|
|
193
|
+
subject: str
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class TaskTest(Task):
|
|
197
|
+
PROVIDER = Task.PROVIDER_FMTR
|
|
198
|
+
MODEL_ID = Task.MODEL_ID_FMTR
|
|
199
|
+
TypeOutput = TestOutput
|
|
200
|
+
SYSTEM_PROMPT_STATIC = 'Tell the user jokes.'
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def tool_output(self) -> OutputSpec[TestOutput]:
|
|
204
|
+
return NativeOutput(self.TypeOutput)
|
|
205
|
+
|
|
206
|
+
def add_system_prompt(self, ctx: RunContext[TestDeps]) -> str:
|
|
207
|
+
return f'The jokes must be in the {ctx.deps.lang} language.'
|
|
208
|
+
|
|
209
|
+
def get_prompt(self, deps: Optional[TestDeps]) -> str:
|
|
210
|
+
return f'Tell me one about {deps.subject}.'
|
|
97
211
|
|
|
98
212
|
task = TaskTest()
|
|
99
|
-
|
|
100
|
-
|
|
213
|
+
deps = TestDeps(lang='English', subject='eggs')
|
|
214
|
+
result1 = task.sync_runner(task.run(deps=deps))
|
|
215
|
+
result1
|
|
216
|
+
|
|
217
|
+
deps = TestDeps(lang='German', subject='sausages')
|
|
218
|
+
result2 = task.sync_runner(task.run(deps=deps))
|
|
219
|
+
result2
|
|
@@ -266,6 +266,7 @@ class BulkInferenceManager:
|
|
|
266
266
|
yield ids_output
|
|
267
267
|
|
|
268
268
|
except RuntimeError as exception:
|
|
269
|
+
# Instability causes CUBLAS_STATUS in str(exception) too
|
|
269
270
|
if "CUDA out of memory" in str(exception):
|
|
270
271
|
logger.warning(f"Ran out of memory. Reducing batch size: {repr(exception)}")
|
|
271
272
|
batcher.reduce()
|
|
@@ -412,5 +413,5 @@ def tst_tool():
|
|
|
412
413
|
|
|
413
414
|
|
|
414
415
|
if __name__ == '__main__':
|
|
415
|
-
texts =
|
|
416
|
+
texts = tst()
|
|
416
417
|
texts
|
fmtr/tools/api_tools.py
CHANGED
|
@@ -3,7 +3,7 @@ from dataclasses import dataclass
|
|
|
3
3
|
from fastapi import FastAPI, Request
|
|
4
4
|
from typing import Callable, List, Optional, Union
|
|
5
5
|
|
|
6
|
-
from fmtr.tools
|
|
6
|
+
from fmtr.tools import environment_tools
|
|
7
7
|
from fmtr.tools.iterator_tools import enlist
|
|
8
8
|
from fmtr.tools.logging_tools import logger
|
|
9
9
|
|
|
@@ -24,7 +24,7 @@ class Endpoint:
|
|
|
24
24
|
self.tags = enlist(self.tags)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class
|
|
27
|
+
class Base:
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
30
|
Simple API base class, generalising endpoint-as-method config.
|
|
@@ -33,6 +33,8 @@ class ApiBase:
|
|
|
33
33
|
TITLE = 'Base API'
|
|
34
34
|
HOST = '0.0.0.0'
|
|
35
35
|
PORT = 8080
|
|
36
|
+
SWAGGER_PARAMS = dict(tryItOutEnabled=True)
|
|
37
|
+
URL_DOCS = '/docs'
|
|
36
38
|
|
|
37
39
|
def add_endpoint(self, endpoint: Endpoint):
|
|
38
40
|
"""
|
|
@@ -51,12 +53,13 @@ class ApiBase:
|
|
|
51
53
|
)(endpoint.method)
|
|
52
54
|
|
|
53
55
|
def __init__(self):
|
|
54
|
-
self.app = FastAPI(title=self.TITLE)
|
|
56
|
+
self.app = FastAPI(title=self.TITLE, swagger_ui_parameters=self.SWAGGER_PARAMS, docs_url=self.URL_DOCS)
|
|
57
|
+
logger.instrument_fastapi(self.app)
|
|
55
58
|
|
|
56
59
|
for endpoint in self.get_endpoints():
|
|
57
60
|
self.add_endpoint(endpoint)
|
|
58
61
|
|
|
59
|
-
if
|
|
62
|
+
if environment_tools.IS_DEV:
|
|
60
63
|
self.app.exception_handler(Exception)(self.handle_exception)
|
|
61
64
|
|
|
62
65
|
def get_endpoints(self) -> List[Endpoint]:
|
|
@@ -94,4 +97,4 @@ class ApiBase:
|
|
|
94
97
|
|
|
95
98
|
|
|
96
99
|
if __name__ == '__main__':
|
|
97
|
-
|
|
100
|
+
Base.launch()
|
fmtr/tools/caching_tools.py
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import cachetools
|
|
2
|
+
from datetime import timedelta, datetime
|
|
1
3
|
from diskcache import Cache
|
|
2
4
|
|
|
3
|
-
from fmtr.tools import
|
|
5
|
+
from fmtr.tools.constants import Constants
|
|
6
|
+
from fmtr.tools.logging_tools import logger
|
|
7
|
+
from fmtr.tools.path_tools.path_tools import Path
|
|
4
8
|
|
|
5
9
|
|
|
6
10
|
class Dump(dict):
|
|
@@ -31,9 +35,9 @@ class Disk(Cache):
|
|
|
31
35
|
if not path.parent.exists():
|
|
32
36
|
raise FileNotFoundError(f"Directory {path.parent=} does not exist")
|
|
33
37
|
if path and not path.exists():
|
|
34
|
-
logger.warning(f'Cache does not exist. Will be created.
|
|
38
|
+
logger.warning(f'Cache does not exist. Will be created. {str(path)=}...')
|
|
35
39
|
|
|
36
|
-
logger.info(f'Initializing Disk Cache
|
|
40
|
+
logger.info(f'Initializing Disk Cache {str(path)=}...')
|
|
37
41
|
|
|
38
42
|
super().__init__(directory=str(path / self.ROOT_KEY), **settings)
|
|
39
43
|
|
|
@@ -95,7 +99,101 @@ class Disk(Cache):
|
|
|
95
99
|
return self.dump()
|
|
96
100
|
|
|
97
101
|
|
|
102
|
+
class TLRU(cachetools.TLRUCache):
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
Subclass to include logging and simplify global TTU
|
|
106
|
+
|
|
107
|
+
"""
|
|
108
|
+
MASK_MAPPING = '{key} ' + Constants.ARROW + ' {value}'
|
|
109
|
+
|
|
110
|
+
def __init__(self, maxsize=1_024, timer=datetime.now, getsizeof=None, ttu_static=None, desc=None):
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
Add overridable TTU method
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
super().__init__(maxsize=maxsize, ttu=self.get_ttu, timer=timer, getsizeof=getsizeof)
|
|
117
|
+
self.ttu_static = ttu_static
|
|
118
|
+
self.desc = desc
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def cache_desc(self):
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
Friendly description of cache
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
desc = self.desc or self.__class__.__name__
|
|
128
|
+
return desc
|
|
129
|
+
|
|
130
|
+
def get_ttu(self, _key, value, now) -> float | timedelta:
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
Default implementation just adds on the static TTU
|
|
134
|
+
|
|
135
|
+
"""
|
|
136
|
+
return now + self.ttu_static
|
|
137
|
+
|
|
138
|
+
def expire(self, time=None):
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
Log expiry
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
items = super().expire(time)
|
|
145
|
+
if not items:
|
|
146
|
+
return items
|
|
147
|
+
|
|
148
|
+
with logger.span(f'{self.desc} cache expiry {len(items)=}...'):
|
|
149
|
+
for key, value in items:
|
|
150
|
+
logger.debug(self.MASK_MAPPING.format(key=key, value=value))
|
|
151
|
+
|
|
152
|
+
return items
|
|
153
|
+
|
|
154
|
+
def popitem(self):
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
Log eviction
|
|
158
|
+
|
|
159
|
+
"""
|
|
160
|
+
key, value = super().popitem()
|
|
161
|
+
logger.debug(f'{self.desc} cache eviction: {self.MASK_MAPPING.format(key=key, value=value)}')
|
|
162
|
+
return key, value
|
|
163
|
+
|
|
164
|
+
def dump(self):
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
Dump contents
|
|
168
|
+
|
|
169
|
+
"""
|
|
170
|
+
data = Dump(self.items())
|
|
171
|
+
return data
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def data(self):
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
Dump as property
|
|
178
|
+
|
|
179
|
+
"""
|
|
180
|
+
return self.dump()
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
98
184
|
if __name__ == '__main__':
|
|
185
|
+
sec10 = timedelta(seconds=10)
|
|
186
|
+
c = TLRU(ttu_static=sec10, maxsize=2, desc='Test Data')
|
|
187
|
+
c['test'] = 'val'
|
|
188
|
+
c['test2'] = 'val2'
|
|
189
|
+
c['test3'] = 'val3'
|
|
190
|
+
c
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
99
197
|
path_tmp_cache = Path.cwd().parent.parent / 'data' / 'cache'
|
|
100
198
|
tc = Disk(path_tmp_cache)
|
|
101
199
|
|