langchain-timbr 2.1.6__py3-none-any.whl → 2.1.7__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.
- langchain_timbr/__init__.py +1 -1
- langchain_timbr/_version.py +2 -2
- langchain_timbr/config.py +1 -1
- langchain_timbr/langchain/execute_timbr_query_chain.py +4 -4
- langchain_timbr/langchain/generate_timbr_sql_chain.py +4 -4
- langchain_timbr/langchain/timbr_sql_agent.py +6 -6
- langchain_timbr/langchain/validate_timbr_sql_chain.py +11 -1
- langchain_timbr/langgraph/execute_timbr_query_node.py +3 -3
- langchain_timbr/langgraph/generate_timbr_sql_node.py +3 -3
- langchain_timbr/langgraph/validate_timbr_query_node.py +6 -0
- langchain_timbr/utils/prompt_service.py +26 -0
- langchain_timbr/utils/timbr_llm_utils.py +124 -132
- langchain_timbr/utils/timbr_utils.py +39 -0
- {langchain_timbr-2.1.6.dist-info → langchain_timbr-2.1.7.dist-info}/METADATA +1 -1
- langchain_timbr-2.1.7.dist-info/RECORD +28 -0
- langchain_timbr-2.1.6.dist-info/RECORD +0 -28
- {langchain_timbr-2.1.6.dist-info → langchain_timbr-2.1.7.dist-info}/WHEEL +0 -0
- {langchain_timbr-2.1.6.dist-info → langchain_timbr-2.1.7.dist-info}/licenses/LICENSE +0 -0
langchain_timbr/__init__.py
CHANGED
langchain_timbr/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '2.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 1,
|
|
31
|
+
__version__ = version = '2.1.7'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 1, 7)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
langchain_timbr/config.py
CHANGED
|
@@ -30,5 +30,5 @@ llm_api_version = os.environ.get('LLM_API_VERSION', None)
|
|
|
30
30
|
llm_scope = os.environ.get('LLM_SCOPE', "https://cognitiveservices.azure.com/.default") # e.g. "api://<your-client-id>/.default"
|
|
31
31
|
|
|
32
32
|
# Whether to enable reasoning during SQL generation
|
|
33
|
-
|
|
33
|
+
enable_reasoning = to_boolean(os.environ.get('ENABLE_REASONING', 'false'))
|
|
34
34
|
reasoning_steps = to_integer(os.environ.get('REASONING_STEPS', 2))
|
|
@@ -42,7 +42,7 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
42
42
|
is_jwt: Optional[bool] = False,
|
|
43
43
|
jwt_tenant_id: Optional[str] = None,
|
|
44
44
|
conn_params: Optional[dict] = None,
|
|
45
|
-
|
|
45
|
+
enable_reasoning: Optional[bool] = config.enable_reasoning,
|
|
46
46
|
reasoning_steps: Optional[int] = config.reasoning_steps,
|
|
47
47
|
debug: Optional[bool] = False,
|
|
48
48
|
**kwargs,
|
|
@@ -71,7 +71,7 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
71
71
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
72
72
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
73
73
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
74
|
-
:param
|
|
74
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
75
75
|
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
76
76
|
:param kwargs: Additional arguments to pass to the base
|
|
77
77
|
:return: A list of rows from the Timbr query
|
|
@@ -141,7 +141,7 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
141
141
|
self._jwt_tenant_id = jwt_tenant_id
|
|
142
142
|
self._debug = to_boolean(debug)
|
|
143
143
|
self._conn_params = conn_params or {}
|
|
144
|
-
self.
|
|
144
|
+
self._enable_reasoning = to_boolean(enable_reasoning)
|
|
145
145
|
self._reasoning_steps = to_integer(reasoning_steps)
|
|
146
146
|
|
|
147
147
|
|
|
@@ -215,7 +215,7 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
215
215
|
note=(self._note or '') + err_txt,
|
|
216
216
|
db_is_case_sensitive=self._db_is_case_sensitive,
|
|
217
217
|
graph_depth=self._graph_depth,
|
|
218
|
-
|
|
218
|
+
enable_reasoning=self._enable_reasoning,
|
|
219
219
|
reasoning_steps=self._reasoning_steps,
|
|
220
220
|
debug=self._debug,
|
|
221
221
|
)
|
|
@@ -39,7 +39,7 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
39
39
|
is_jwt: Optional[bool] = False,
|
|
40
40
|
jwt_tenant_id: Optional[str] = None,
|
|
41
41
|
conn_params: Optional[dict] = None,
|
|
42
|
-
|
|
42
|
+
enable_reasoning: Optional[bool] = config.enable_reasoning,
|
|
43
43
|
reasoning_steps: Optional[int] = config.reasoning_steps,
|
|
44
44
|
debug: Optional[bool] = False,
|
|
45
45
|
**kwargs,
|
|
@@ -66,7 +66,7 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
66
66
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
67
67
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
68
68
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
69
|
-
:param
|
|
69
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
70
70
|
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
71
71
|
:param debug: Whether to enable debug mode for detailed logging
|
|
72
72
|
:param kwargs: Additional arguments to pass to the base
|
|
@@ -134,7 +134,7 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
134
134
|
self._jwt_tenant_id = jwt_tenant_id
|
|
135
135
|
self._debug = to_boolean(debug)
|
|
136
136
|
self._conn_params = conn_params or {}
|
|
137
|
-
self.
|
|
137
|
+
self._enable_reasoning = to_boolean(enable_reasoning)
|
|
138
138
|
self._reasoning_steps = to_integer(reasoning_steps)
|
|
139
139
|
|
|
140
140
|
|
|
@@ -191,7 +191,7 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
191
191
|
note=self._note,
|
|
192
192
|
db_is_case_sensitive=self._db_is_case_sensitive,
|
|
193
193
|
graph_depth=self._graph_depth,
|
|
194
|
-
|
|
194
|
+
enable_reasoning=self._enable_reasoning,
|
|
195
195
|
reasoning_steps=self._reasoning_steps,
|
|
196
196
|
debug=self._debug,
|
|
197
197
|
)
|
|
@@ -35,7 +35,7 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
35
35
|
is_jwt: Optional[bool] = False,
|
|
36
36
|
jwt_tenant_id: Optional[str] = None,
|
|
37
37
|
conn_params: Optional[dict] = None,
|
|
38
|
-
|
|
38
|
+
enable_reasoning: Optional[bool] = config.enable_reasoning,
|
|
39
39
|
reasoning_steps: Optional[int] = config.reasoning_steps,
|
|
40
40
|
debug: Optional[bool] = False
|
|
41
41
|
):
|
|
@@ -64,7 +64,7 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
64
64
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
65
65
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
66
66
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
67
|
-
:param
|
|
67
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
68
68
|
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
69
69
|
|
|
70
70
|
## Example
|
|
@@ -118,7 +118,7 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
118
118
|
is_jwt=to_boolean(is_jwt),
|
|
119
119
|
jwt_tenant_id=jwt_tenant_id,
|
|
120
120
|
conn_params=conn_params,
|
|
121
|
-
|
|
121
|
+
enable_reasoning=to_boolean(enable_reasoning),
|
|
122
122
|
reasoning_steps=to_integer(reasoning_steps),
|
|
123
123
|
debug=to_boolean(debug),
|
|
124
124
|
)
|
|
@@ -345,7 +345,7 @@ def create_timbr_sql_agent(
|
|
|
345
345
|
is_jwt: Optional[bool] = False,
|
|
346
346
|
jwt_tenant_id: Optional[str] = None,
|
|
347
347
|
conn_params: Optional[dict] = None,
|
|
348
|
-
|
|
348
|
+
enable_reasoning: Optional[bool] = config.enable_reasoning,
|
|
349
349
|
reasoning_steps: Optional[int] = config.reasoning_steps,
|
|
350
350
|
debug: Optional[bool] = False
|
|
351
351
|
) -> AgentExecutor:
|
|
@@ -376,7 +376,7 @@ def create_timbr_sql_agent(
|
|
|
376
376
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
377
377
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
378
378
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
379
|
-
:param
|
|
379
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
380
380
|
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
381
381
|
|
|
382
382
|
Returns:
|
|
@@ -444,7 +444,7 @@ def create_timbr_sql_agent(
|
|
|
444
444
|
is_jwt=is_jwt,
|
|
445
445
|
jwt_tenant_id=jwt_tenant_id,
|
|
446
446
|
conn_params=conn_params,
|
|
447
|
-
|
|
447
|
+
enable_reasoning=enable_reasoning,
|
|
448
448
|
reasoning_steps=reasoning_steps,
|
|
449
449
|
debug=debug,
|
|
450
450
|
)
|
|
@@ -40,6 +40,8 @@ class ValidateTimbrSqlChain(Chain):
|
|
|
40
40
|
is_jwt: Optional[bool] = False,
|
|
41
41
|
jwt_tenant_id: Optional[str] = None,
|
|
42
42
|
conn_params: Optional[dict] = None,
|
|
43
|
+
enable_reasoning: Optional[bool] = config.enable_reasoning,
|
|
44
|
+
reasoning_steps: Optional[int] = config.reasoning_steps,
|
|
43
45
|
debug: Optional[bool] = False,
|
|
44
46
|
**kwargs,
|
|
45
47
|
):
|
|
@@ -64,6 +66,8 @@ class ValidateTimbrSqlChain(Chain):
|
|
|
64
66
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
65
67
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
66
68
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
69
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
70
|
+
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
67
71
|
:param kwargs: Additional arguments to pass to the base
|
|
68
72
|
|
|
69
73
|
## Example
|
|
@@ -127,8 +131,10 @@ class ValidateTimbrSqlChain(Chain):
|
|
|
127
131
|
self._verify_ssl = to_boolean(verify_ssl)
|
|
128
132
|
self._is_jwt = to_boolean(is_jwt)
|
|
129
133
|
self._jwt_tenant_id = jwt_tenant_id
|
|
130
|
-
self._debug = to_boolean(debug)
|
|
131
134
|
self._conn_params = conn_params or {}
|
|
135
|
+
self._enable_reasoning = to_boolean(enable_reasoning)
|
|
136
|
+
self._reasoning_steps = to_integer(reasoning_steps)
|
|
137
|
+
self._debug = to_boolean(debug)
|
|
132
138
|
|
|
133
139
|
|
|
134
140
|
@property
|
|
@@ -193,6 +199,8 @@ class ValidateTimbrSqlChain(Chain):
|
|
|
193
199
|
note=f"{prompt_extension}The original SQL query (`{sql}`) was invalid with this error from query {error}. Please take this in consideration while generating the query.",
|
|
194
200
|
db_is_case_sensitive=self._db_is_case_sensitive,
|
|
195
201
|
graph_depth=self._graph_depth,
|
|
202
|
+
enable_reasoning=self._enable_reasoning,
|
|
203
|
+
reasoning_steps=self._reasoning_steps,
|
|
196
204
|
debug=self._debug,
|
|
197
205
|
)
|
|
198
206
|
sql = generate_res.get("sql", "")
|
|
@@ -200,6 +208,7 @@ class ValidateTimbrSqlChain(Chain):
|
|
|
200
208
|
concept = generate_res.get("concept", self._concept)
|
|
201
209
|
usage_metadata.update(generate_res.get("usage_metadata", {}))
|
|
202
210
|
is_sql_valid = generate_res.get("is_sql_valid")
|
|
211
|
+
reasoning_status = generate_res.get("reasoning_status")
|
|
203
212
|
error = generate_res.get("error")
|
|
204
213
|
|
|
205
214
|
return {
|
|
@@ -208,5 +217,6 @@ class ValidateTimbrSqlChain(Chain):
|
|
|
208
217
|
"concept": concept,
|
|
209
218
|
"is_sql_valid": is_sql_valid,
|
|
210
219
|
"error": error,
|
|
220
|
+
"reasoning_status": reasoning_status,
|
|
211
221
|
self.usage_metadata_key: usage_metadata,
|
|
212
222
|
}
|
|
@@ -36,7 +36,7 @@ class ExecuteSemanticQueryNode:
|
|
|
36
36
|
is_jwt: Optional[bool] = False,
|
|
37
37
|
jwt_tenant_id: Optional[str] = None,
|
|
38
38
|
conn_params: Optional[dict] = None,
|
|
39
|
-
|
|
39
|
+
enable_reasoning: Optional[bool] = config.enable_reasoning,
|
|
40
40
|
reasoning_steps: Optional[int] = config.reasoning_steps,
|
|
41
41
|
debug: Optional[bool] = False,
|
|
42
42
|
**kwargs,
|
|
@@ -65,7 +65,7 @@ class ExecuteSemanticQueryNode:
|
|
|
65
65
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
66
66
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
67
67
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
68
|
-
:param
|
|
68
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
69
69
|
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
70
70
|
:return: A list of rows from the Timbr query
|
|
71
71
|
"""
|
|
@@ -93,7 +93,7 @@ class ExecuteSemanticQueryNode:
|
|
|
93
93
|
is_jwt=is_jwt,
|
|
94
94
|
jwt_tenant_id=jwt_tenant_id,
|
|
95
95
|
conn_params=conn_params,
|
|
96
|
-
|
|
96
|
+
enable_reasoning=enable_reasoning,
|
|
97
97
|
reasoning_steps=reasoning_steps,
|
|
98
98
|
debug=debug,
|
|
99
99
|
**kwargs,
|
|
@@ -33,7 +33,7 @@ class GenerateTimbrSqlNode:
|
|
|
33
33
|
is_jwt: Optional[bool] = False,
|
|
34
34
|
jwt_tenant_id: Optional[str] = None,
|
|
35
35
|
conn_params: Optional[dict] = None,
|
|
36
|
-
|
|
36
|
+
enable_reasoning: Optional[bool] = config.enable_reasoning,
|
|
37
37
|
reasoning_steps: Optional[int] = config.reasoning_steps,
|
|
38
38
|
debug: Optional[bool] = False,
|
|
39
39
|
**kwargs,
|
|
@@ -60,7 +60,7 @@ class GenerateTimbrSqlNode:
|
|
|
60
60
|
:param is_jwt: Whether to use JWT authentication (default: False)
|
|
61
61
|
:param jwt_tenant_id: Tenant ID for JWT authentication when using multi-tenant setup
|
|
62
62
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
63
|
-
:param
|
|
63
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
64
64
|
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
65
65
|
"""
|
|
66
66
|
self.chain = GenerateTimbrSqlChain(
|
|
@@ -85,7 +85,7 @@ class GenerateTimbrSqlNode:
|
|
|
85
85
|
is_jwt=is_jwt,
|
|
86
86
|
jwt_tenant_id=jwt_tenant_id,
|
|
87
87
|
conn_params=conn_params,
|
|
88
|
-
|
|
88
|
+
enable_reasoning=enable_reasoning,
|
|
89
89
|
reasoning_steps=reasoning_steps,
|
|
90
90
|
debug=debug,
|
|
91
91
|
**kwargs,
|
|
@@ -33,6 +33,8 @@ class ValidateSemanticSqlNode:
|
|
|
33
33
|
is_jwt: Optional[bool] = False,
|
|
34
34
|
jwt_tenant_id: Optional[str] = None,
|
|
35
35
|
conn_params: Optional[dict] = None,
|
|
36
|
+
enable_reasoning: Optional[bool] = False,
|
|
37
|
+
reasoning_steps: Optional[int] = 2,
|
|
36
38
|
debug: Optional[bool] = False,
|
|
37
39
|
**kwargs,
|
|
38
40
|
):
|
|
@@ -57,6 +59,8 @@ class ValidateSemanticSqlNode:
|
|
|
57
59
|
:param is_jwt: Whether to use JWT authentication (default: False)
|
|
58
60
|
:param jwt_tenant_id: Tenant ID for JWT authentication when using multi-tenant setup
|
|
59
61
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
62
|
+
:param enable_reasoning: Whether to enable reasoning during SQL generation (default is False).
|
|
63
|
+
:param reasoning_steps: Number of reasoning steps to perform if reasoning is enabled (default is 2).
|
|
60
64
|
"""
|
|
61
65
|
self.chain = ValidateTimbrSqlChain(
|
|
62
66
|
llm=llm,
|
|
@@ -79,6 +83,8 @@ class ValidateSemanticSqlNode:
|
|
|
79
83
|
is_jwt=is_jwt,
|
|
80
84
|
jwt_tenant_id=jwt_tenant_id,
|
|
81
85
|
conn_params=conn_params,
|
|
86
|
+
enable_reasoning=enable_reasoning,
|
|
87
|
+
reasoning_steps=reasoning_steps,
|
|
82
88
|
debug=debug,
|
|
83
89
|
**kwargs,
|
|
84
90
|
)
|
|
@@ -184,6 +184,16 @@ class PromptService:
|
|
|
184
184
|
return self._fetch_template("llm_prompts/generate_sql")
|
|
185
185
|
|
|
186
186
|
|
|
187
|
+
def get_generate_sql_reasoning_template(self) -> ChatPromptTemplate:
|
|
188
|
+
"""
|
|
189
|
+
Get generate SQL reasoning template from API service (cached)
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
ChatPromptTemplate object
|
|
193
|
+
"""
|
|
194
|
+
return self._fetch_template("llm_prompts/generate_sql_reasoning")
|
|
195
|
+
|
|
196
|
+
|
|
187
197
|
def get_generate_answer_template(self) -> ChatPromptTemplate:
|
|
188
198
|
"""
|
|
189
199
|
Get generate answer template from API service (cached)
|
|
@@ -264,6 +274,22 @@ def get_generate_sql_prompt_template(
|
|
|
264
274
|
return PromptTemplateWrapper(prompt_service, "get_generate_sql_template")
|
|
265
275
|
|
|
266
276
|
|
|
277
|
+
def get_generate_sql_reasoning_prompt_template(
|
|
278
|
+
conn_params: Optional[dict] = None
|
|
279
|
+
) -> PromptTemplateWrapper:
|
|
280
|
+
"""
|
|
281
|
+
Get generate SQL reasoning prompt template wrapper
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
conn_params: Connection parameters including url, token, is_jwt, and jwt_tenant_id
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
PromptTemplateWrapper for generate SQL reasoning
|
|
288
|
+
"""
|
|
289
|
+
prompt_service = PromptService(conn_params=conn_params)
|
|
290
|
+
return PromptTemplateWrapper(prompt_service, "get_generate_sql_reasoning_template")
|
|
291
|
+
|
|
292
|
+
|
|
267
293
|
def get_qa_prompt_template(
|
|
268
294
|
conn_params: Optional[dict] = None
|
|
269
295
|
) -> PromptTemplateWrapper:
|
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
from typing import Any, Optional
|
|
2
2
|
from langchain.llms.base import LLM
|
|
3
|
-
import base64, hashlib
|
|
4
|
-
from cryptography.fernet import Fernet
|
|
5
3
|
from datetime import datetime
|
|
6
4
|
import concurrent.futures
|
|
7
5
|
import json
|
|
8
|
-
from langchain_core.messages import HumanMessage, SystemMessage
|
|
9
6
|
|
|
10
|
-
from .timbr_utils import get_datasources, get_tags, get_concepts, get_concept_properties, validate_sql, get_properties_description, get_relationships_description
|
|
7
|
+
from .timbr_utils import get_datasources, get_tags, get_concepts, get_concept_properties, validate_sql, get_properties_description, get_relationships_description, cache_with_version_check, encrypt_prompt
|
|
11
8
|
from .prompt_service import (
|
|
12
9
|
get_determine_concept_prompt_template,
|
|
13
10
|
get_generate_sql_prompt_template,
|
|
11
|
+
get_generate_sql_reasoning_prompt_template,
|
|
14
12
|
get_qa_prompt_template
|
|
15
13
|
)
|
|
16
14
|
from ..config import llm_timeout
|
|
17
15
|
|
|
18
|
-
|
|
19
16
|
def _clean_snowflake_prompt(prompt: Any) -> None:
|
|
20
17
|
import re
|
|
21
18
|
|
|
@@ -55,14 +52,6 @@ def _clean_snowflake_prompt(prompt: Any) -> None:
|
|
|
55
52
|
prompt[1].content = clean_func(prompt[1].content) # User message
|
|
56
53
|
|
|
57
54
|
|
|
58
|
-
def generate_key() -> bytes:
|
|
59
|
-
"""Generate a new Fernet secret key."""
|
|
60
|
-
passcode = b"lucylit2025"
|
|
61
|
-
hlib = hashlib.md5()
|
|
62
|
-
hlib.update(passcode)
|
|
63
|
-
return base64.urlsafe_b64encode(hlib.hexdigest().encode('utf-8'))
|
|
64
|
-
|
|
65
|
-
|
|
66
55
|
def _call_llm_with_timeout(llm: LLM, prompt: Any, timeout: int = 60) -> Any:
|
|
67
56
|
"""
|
|
68
57
|
Call LLM with timeout to prevent hanging.
|
|
@@ -91,35 +80,9 @@ def _call_llm_with_timeout(llm: LLM, prompt: Any, timeout: int = 60) -> Any:
|
|
|
91
80
|
except Exception as e:
|
|
92
81
|
raise e
|
|
93
82
|
|
|
94
|
-
ENCRYPT_KEY = generate_key()
|
|
95
83
|
MEASURES_DESCRIPTION = "The following columns are calculated measures and can only be aggregated with an aggregate function: COUNT/SUM/AVG/MIN/MAX (count distinct is not allowed)"
|
|
96
84
|
TRANSITIVE_RELATIONSHIP_DESCRIPTION = "Transitive relationship columns allow you to access data through multiple relationship hops. These columns follow the pattern `<relationship_name>[<table_name>*<number>].<column_name>` where the number after the asterisk (*) indicates how many relationship levels to traverse. For example, `acquired_by[company*4].company_name` means 'go through up to 4 levels of the acquired_by relationship to get the company name', while columns ending with '_transitivity_level' indicate the actual relationship depth (Cannot be null or 0 - level 1 represents direct relationships, while levels 2, 3, 4, etc. represent indirect relationships through multiple hops. To filter by relationship type, use `_transitivity_level = 1` for direct relationships only, `_transitivity_level > 1` for indirect relationships only."
|
|
97
85
|
|
|
98
|
-
def encrypt_prompt(prompt: Any, key: Optional[bytes] = ENCRYPT_KEY) -> bytes:
|
|
99
|
-
"""Serialize & encrypt the prompt; returns a URL-safe token."""
|
|
100
|
-
# build prompt_text as before…
|
|
101
|
-
if isinstance(prompt, str):
|
|
102
|
-
text = prompt
|
|
103
|
-
elif isinstance(prompt, list):
|
|
104
|
-
parts = []
|
|
105
|
-
for message in prompt:
|
|
106
|
-
if hasattr(message, "content"):
|
|
107
|
-
parts.append(f"{message.type}: {message.content}")
|
|
108
|
-
else:
|
|
109
|
-
parts.append(str(message))
|
|
110
|
-
text = "\n".join(parts)
|
|
111
|
-
else:
|
|
112
|
-
text = str(prompt)
|
|
113
|
-
|
|
114
|
-
f = Fernet(key)
|
|
115
|
-
return f.encrypt(text.encode()).decode('utf-8')
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def decrypt_prompt(token: bytes, key: bytes) -> str:
|
|
119
|
-
"""Decrypt the token and return the original prompt string."""
|
|
120
|
-
f = Fernet(key)
|
|
121
|
-
return f.decrypt(token).decode()
|
|
122
|
-
|
|
123
86
|
|
|
124
87
|
def _prompt_to_string(prompt: Any) -> str:
|
|
125
88
|
prompt_text = ''
|
|
@@ -187,6 +150,7 @@ def _get_response_text(response: Any) -> str:
|
|
|
187
150
|
|
|
188
151
|
return response_text
|
|
189
152
|
|
|
153
|
+
|
|
190
154
|
def _extract_usage_metadata(response: Any) -> dict:
|
|
191
155
|
"""
|
|
192
156
|
Extract usage metadata from LLM response across different providers.
|
|
@@ -287,6 +251,7 @@ def _extract_usage_metadata(response: Any) -> dict:
|
|
|
287
251
|
|
|
288
252
|
return usage_metadata
|
|
289
253
|
|
|
254
|
+
|
|
290
255
|
def determine_concept(
|
|
291
256
|
question: str,
|
|
292
257
|
llm: LLM,
|
|
@@ -479,10 +444,11 @@ def _get_active_datasource(conn_params: dict) -> dict:
|
|
|
479
444
|
return datasources[0] if datasources else None
|
|
480
445
|
|
|
481
446
|
|
|
482
|
-
def
|
|
447
|
+
def _evaluate_sql_enable_reasoning(
|
|
483
448
|
question: str,
|
|
484
449
|
sql_query: str,
|
|
485
450
|
llm: LLM,
|
|
451
|
+
conn_params: dict,
|
|
486
452
|
timeout: int,
|
|
487
453
|
) -> dict:
|
|
488
454
|
"""
|
|
@@ -491,49 +457,17 @@ def _evaluate_sql_with_reasoning(
|
|
|
491
457
|
Returns:
|
|
492
458
|
dict with 'assessment' ('correct'|'partial'|'incorrect') and 'reasoning'
|
|
493
459
|
"""
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
* `measure.<measure_name>` - References computed measures (e.g., measure.total_balance_amount)
|
|
500
|
-
* `<relationship>[target_table].<property>` - Graph traversal syntax (e.g., has_account[Account].account_name)
|
|
501
|
-
* These are translated by Timbr to standard SQL before execution
|
|
502
|
-
- DO NOT mark queries as incorrect based on field name syntax - Timbr validates this before execution
|
|
503
|
-
|
|
504
|
-
Evaluate whether the generated query correctly addresses the business question:
|
|
505
|
-
- **correct**: The query fully and accurately answers the question
|
|
506
|
-
- **partial**: The query is partially correct or incomplete
|
|
507
|
-
- **incorrect**: The query does not address the question or is wrong
|
|
508
|
-
|
|
509
|
-
Return your evaluation as a JSON object with this exact structure:
|
|
510
|
-
{
|
|
511
|
-
"assessment": "<correct|partial|incorrect>",
|
|
512
|
-
"reasoning": "<short but precise sentence explaining your assessment>"
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
Be concise and objective."""
|
|
516
|
-
|
|
517
|
-
user_prompt = f"""**Business Question:**
|
|
518
|
-
{question}
|
|
519
|
-
|
|
520
|
-
**Generated SQL Query:**
|
|
521
|
-
```sql
|
|
522
|
-
{sql_query}
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
Please evaluate this result."""
|
|
526
|
-
|
|
527
|
-
messages = [
|
|
528
|
-
SystemMessage(content=system_prompt),
|
|
529
|
-
HumanMessage(content=user_prompt)
|
|
530
|
-
]
|
|
460
|
+
generate_sql_reasoning_template = get_generate_sql_reasoning_prompt_template(conn_params)
|
|
461
|
+
prompt = generate_sql_reasoning_template.format_messages(
|
|
462
|
+
question=question.strip(),
|
|
463
|
+
sql_query=sql_query.strip(),
|
|
464
|
+
)
|
|
531
465
|
|
|
532
|
-
apx_token_count = _calculate_token_count(llm,
|
|
466
|
+
apx_token_count = _calculate_token_count(llm, prompt)
|
|
533
467
|
if hasattr(llm, "_llm_type") and "snowflake" in llm._llm_type:
|
|
534
|
-
_clean_snowflake_prompt(
|
|
468
|
+
_clean_snowflake_prompt(prompt)
|
|
535
469
|
|
|
536
|
-
response = _call_llm_with_timeout(llm,
|
|
470
|
+
response = _call_llm_with_timeout(llm, prompt, timeout=timeout)
|
|
537
471
|
|
|
538
472
|
# Extract JSON from response content (handle markdown code blocks)
|
|
539
473
|
content = response.content.strip()
|
|
@@ -559,6 +493,87 @@ Please evaluate this result."""
|
|
|
559
493
|
}
|
|
560
494
|
|
|
561
495
|
|
|
496
|
+
@cache_with_version_check
|
|
497
|
+
def _build_sql_generation_context(
|
|
498
|
+
conn_params: dict,
|
|
499
|
+
schema: str,
|
|
500
|
+
concept: str,
|
|
501
|
+
concept_metadata: dict,
|
|
502
|
+
graph_depth: int,
|
|
503
|
+
include_tags: Optional[str],
|
|
504
|
+
exclude_properties: Optional[list],
|
|
505
|
+
db_is_case_sensitive: bool,
|
|
506
|
+
max_limit: int,
|
|
507
|
+
) -> dict:
|
|
508
|
+
"""
|
|
509
|
+
Prepare the complete SQL generation context by gathering all necessary metadata.
|
|
510
|
+
|
|
511
|
+
This includes:
|
|
512
|
+
- Datasource information
|
|
513
|
+
- Concept properties (columns, measures, relationships)
|
|
514
|
+
- Property tags
|
|
515
|
+
- Building column/measure/relationship descriptions
|
|
516
|
+
- Assembling the final context dictionary
|
|
517
|
+
|
|
518
|
+
Returns:
|
|
519
|
+
dict containing all context needed for SQL generation prompts
|
|
520
|
+
"""
|
|
521
|
+
datasource_type = _get_active_datasource(conn_params).get('target_type')
|
|
522
|
+
|
|
523
|
+
properties_desc = get_properties_description(conn_params=conn_params)
|
|
524
|
+
relationships_desc = get_relationships_description(conn_params=conn_params)
|
|
525
|
+
|
|
526
|
+
concept_properties_metadata = get_concept_properties(
|
|
527
|
+
schema=schema,
|
|
528
|
+
concept_name=concept,
|
|
529
|
+
conn_params=conn_params,
|
|
530
|
+
properties_desc=properties_desc,
|
|
531
|
+
relationships_desc=relationships_desc,
|
|
532
|
+
graph_depth=graph_depth
|
|
533
|
+
)
|
|
534
|
+
columns = concept_properties_metadata.get('columns', [])
|
|
535
|
+
measures = concept_properties_metadata.get('measures', [])
|
|
536
|
+
relationships = concept_properties_metadata.get('relationships', {})
|
|
537
|
+
tags = get_tags(conn_params=conn_params, include_tags=include_tags).get('property_tags')
|
|
538
|
+
|
|
539
|
+
columns_str = _build_columns_str(columns, columns_tags=tags, exclude=exclude_properties)
|
|
540
|
+
measures_str = _build_columns_str(measures, tags, exclude=exclude_properties)
|
|
541
|
+
rel_prop_str = _build_rel_columns_str(relationships, columns_tags=tags, exclude_properties=exclude_properties)
|
|
542
|
+
|
|
543
|
+
if rel_prop_str:
|
|
544
|
+
measures_str += f"\n{rel_prop_str}"
|
|
545
|
+
|
|
546
|
+
# Determine if relationships have transitive properties
|
|
547
|
+
has_transitive_relationships = any(
|
|
548
|
+
rel.get('is_transitive')
|
|
549
|
+
for rel in relationships.values()
|
|
550
|
+
) if relationships else False
|
|
551
|
+
|
|
552
|
+
concept_description = f"- Description: {concept_metadata.get('description')}\n" if concept_metadata and concept_metadata.get('description') else ""
|
|
553
|
+
concept_tags = concept_metadata.get('tags') if concept_metadata and concept_metadata.get('tags') else ""
|
|
554
|
+
|
|
555
|
+
cur_date = datetime.now().strftime("%Y-%m-%d")
|
|
556
|
+
|
|
557
|
+
# Build context descriptions
|
|
558
|
+
sensitivity_txt = "- Ensure value comparisons are case-insensitive, e.g., use LOWER(column) = 'value'.\n" if db_is_case_sensitive else ""
|
|
559
|
+
measures_context = f"- {MEASURES_DESCRIPTION}: {measures_str}\n" if measures_str else ""
|
|
560
|
+
transitive_context = f"- {TRANSITIVE_RELATIONSHIP_DESCRIPTION}\n" if has_transitive_relationships else ""
|
|
561
|
+
|
|
562
|
+
return {
|
|
563
|
+
'cur_date': cur_date,
|
|
564
|
+
'datasource_type': datasource_type or 'standard sql',
|
|
565
|
+
'schema': schema,
|
|
566
|
+
'concept': concept,
|
|
567
|
+
'concept_description': concept_description or "",
|
|
568
|
+
'concept_tags': concept_tags or "",
|
|
569
|
+
'columns_str': columns_str,
|
|
570
|
+
'measures_context': measures_context,
|
|
571
|
+
'transitive_context': transitive_context,
|
|
572
|
+
'sensitivity_txt': sensitivity_txt,
|
|
573
|
+
'max_limit': max_limit,
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
|
|
562
577
|
def _generate_sql_with_llm(
|
|
563
578
|
question: str,
|
|
564
579
|
llm: LLM,
|
|
@@ -639,7 +654,7 @@ def generate_sql(
|
|
|
639
654
|
note: Optional[str] = '',
|
|
640
655
|
db_is_case_sensitive: Optional[bool] = False,
|
|
641
656
|
graph_depth: Optional[int] = 1,
|
|
642
|
-
|
|
657
|
+
enable_reasoning: Optional[bool] = False,
|
|
643
658
|
reasoning_steps: Optional[int] = 2,
|
|
644
659
|
debug: Optional[bool] = False,
|
|
645
660
|
timeout: Optional[int] = None,
|
|
@@ -679,50 +694,6 @@ def generate_sql(
|
|
|
679
694
|
if not concept:
|
|
680
695
|
raise Exception("No relevant concept found for the query.")
|
|
681
696
|
|
|
682
|
-
datasource_type = _get_active_datasource(conn_params).get('target_type')
|
|
683
|
-
|
|
684
|
-
properties_desc = get_properties_description(conn_params=conn_params)
|
|
685
|
-
relationships_desc = get_relationships_description(conn_params=conn_params)
|
|
686
|
-
|
|
687
|
-
concept_properties_metadata = get_concept_properties(schema=schema, concept_name=concept, conn_params=conn_params, properties_desc=properties_desc, relationships_desc=relationships_desc, graph_depth=graph_depth)
|
|
688
|
-
columns, measures, relationships = concept_properties_metadata.get('columns', []), concept_properties_metadata.get('measures', []), concept_properties_metadata.get('relationships', {})
|
|
689
|
-
tags = get_tags(conn_params=conn_params, include_tags=include_tags).get('property_tags')
|
|
690
|
-
|
|
691
|
-
columns_str = _build_columns_str(columns, columns_tags=tags, exclude=exclude_properties)
|
|
692
|
-
measures_str = _build_columns_str(measures, tags, exclude=exclude_properties)
|
|
693
|
-
rel_prop_str = _build_rel_columns_str(relationships, columns_tags=tags, exclude_properties=exclude_properties)
|
|
694
|
-
|
|
695
|
-
if rel_prop_str:
|
|
696
|
-
measures_str += f"\n{rel_prop_str}"
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
# Build context descriptions
|
|
700
|
-
sensitivity_txt = "- Ensure value comparisons are case-insensitive, e.g., use LOWER(column) = 'value'.\n" if db_is_case_sensitive else ""
|
|
701
|
-
measures_context = f"- {MEASURES_DESCRIPTION}: {measures_str}\n" if measures_str else ""
|
|
702
|
-
has_transitive_relationships = any(
|
|
703
|
-
rel.get('is_transitive')
|
|
704
|
-
for rel in relationships.values()
|
|
705
|
-
) if relationships else False
|
|
706
|
-
transitive_context = f"- {TRANSITIVE_RELATIONSHIP_DESCRIPTION}\n" if has_transitive_relationships else ""
|
|
707
|
-
concept_description = f"- Description: {concept_metadata.get('description')}\n" if concept_metadata and concept_metadata.get('description') else ""
|
|
708
|
-
concept_tags = concept_metadata.get('tags') if concept_metadata and concept_metadata.get('tags') else ""
|
|
709
|
-
cur_date = datetime.now().strftime("%Y-%m-%d")
|
|
710
|
-
|
|
711
|
-
# Build context dict for SQL generation
|
|
712
|
-
current_context = {
|
|
713
|
-
'cur_date': cur_date,
|
|
714
|
-
'datasource_type': datasource_type or 'standard sql',
|
|
715
|
-
'schema': schema,
|
|
716
|
-
'concept': concept,
|
|
717
|
-
'concept_description': concept_description or "",
|
|
718
|
-
'concept_tags': concept_tags or "",
|
|
719
|
-
'columns_str': columns_str,
|
|
720
|
-
'measures_context': measures_context,
|
|
721
|
-
'transitive_context': transitive_context,
|
|
722
|
-
'sensitivity_txt': sensitivity_txt,
|
|
723
|
-
'max_limit': max_limit,
|
|
724
|
-
}
|
|
725
|
-
|
|
726
697
|
sql_query = None
|
|
727
698
|
iteration = 0
|
|
728
699
|
is_sql_valid = True
|
|
@@ -737,7 +708,16 @@ def generate_sql(
|
|
|
737
708
|
llm=llm,
|
|
738
709
|
conn_params=conn_params,
|
|
739
710
|
generate_sql_prompt=generate_sql_prompt,
|
|
740
|
-
current_context=
|
|
711
|
+
current_context=_build_sql_generation_context(
|
|
712
|
+
conn_params=conn_params,
|
|
713
|
+
schema=schema,
|
|
714
|
+
concept=concept,
|
|
715
|
+
concept_metadata=concept_metadata,
|
|
716
|
+
graph_depth=graph_depth,
|
|
717
|
+
include_tags=include_tags,
|
|
718
|
+
exclude_properties=exclude_properties,
|
|
719
|
+
db_is_case_sensitive=db_is_case_sensitive,
|
|
720
|
+
max_limit=max_limit),
|
|
741
721
|
note=note + err_txt,
|
|
742
722
|
should_validate_sql=should_validate_sql,
|
|
743
723
|
timeout=timeout,
|
|
@@ -766,18 +746,19 @@ def generate_sql(
|
|
|
766
746
|
raise Exception(error)
|
|
767
747
|
|
|
768
748
|
|
|
769
|
-
if
|
|
749
|
+
if enable_reasoning and sql_query is not None:
|
|
770
750
|
for step in range(reasoning_steps):
|
|
771
751
|
try:
|
|
772
752
|
# Step 1: Evaluate the current SQL
|
|
773
|
-
eval_result =
|
|
753
|
+
eval_result = _evaluate_sql_enable_reasoning(
|
|
774
754
|
question=question,
|
|
775
755
|
sql_query=sql_query,
|
|
776
756
|
llm=llm,
|
|
757
|
+
conn_params=conn_params,
|
|
777
758
|
timeout=timeout,
|
|
778
759
|
)
|
|
779
760
|
|
|
780
|
-
usage_metadata[f'sql_reasoning_step_{step}'] = {
|
|
761
|
+
usage_metadata[f'sql_reasoning_step_{step + 1}'] = {
|
|
781
762
|
"approximate": eval_result['apx_token_count'],
|
|
782
763
|
**eval_result['usage_metadata'],
|
|
783
764
|
}
|
|
@@ -791,24 +772,35 @@ def generate_sql(
|
|
|
791
772
|
# Step 2: Regenerate SQL with feedback
|
|
792
773
|
evaluation_note = note + f"\n\nThe previously generated SQL: `{sql_query}` was assessed as '{evaluation.get('assessment')}' because: {evaluation.get('reasoning', '*could not determine cause*')}. Please provide a corrected SQL query that better answers the question: '{question}'."
|
|
793
774
|
|
|
775
|
+
# Increase graph depth for 2nd+ reasoning attempts, up to max of 3
|
|
776
|
+
context_graph_depth = min(3, int(graph_depth) + step) if graph_depth < 3 and step > 0 else graph_depth
|
|
794
777
|
regen_result = _generate_sql_with_llm(
|
|
795
778
|
question=question,
|
|
796
779
|
llm=llm,
|
|
797
780
|
conn_params=conn_params,
|
|
798
781
|
generate_sql_prompt=generate_sql_prompt,
|
|
799
|
-
current_context=
|
|
782
|
+
current_context=_build_sql_generation_context(
|
|
783
|
+
conn_params=conn_params,
|
|
784
|
+
schema=schema,
|
|
785
|
+
concept=concept,
|
|
786
|
+
concept_metadata=concept_metadata,
|
|
787
|
+
graph_depth=context_graph_depth,
|
|
788
|
+
include_tags=include_tags,
|
|
789
|
+
exclude_properties=exclude_properties,
|
|
790
|
+
db_is_case_sensitive=db_is_case_sensitive,
|
|
791
|
+
max_limit=max_limit),
|
|
800
792
|
note=evaluation_note,
|
|
801
793
|
should_validate_sql=should_validate_sql,
|
|
802
794
|
timeout=timeout,
|
|
803
795
|
debug=debug,
|
|
804
796
|
)
|
|
805
797
|
|
|
806
|
-
usage_metadata[f'generate_sql_reasoning_step_{step}'] = {
|
|
798
|
+
usage_metadata[f'generate_sql_reasoning_step_{step + 1}'] = {
|
|
807
799
|
"approximate": regen_result['apx_token_count'],
|
|
808
800
|
**regen_result['usage_metadata'],
|
|
809
801
|
}
|
|
810
802
|
if debug and 'p_hash' in regen_result:
|
|
811
|
-
usage_metadata[f'generate_sql_reasoning_step_{step}']['p_hash'] = regen_result['p_hash']
|
|
803
|
+
usage_metadata[f'generate_sql_reasoning_step_{step + 1}']['p_hash'] = regen_result['p_hash']
|
|
812
804
|
|
|
813
805
|
sql_query = regen_result['sql']
|
|
814
806
|
is_sql_valid = regen_result['is_valid']
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from typing import Optional, Any
|
|
2
2
|
import time
|
|
3
|
+
import base64
|
|
4
|
+
import hashlib
|
|
3
5
|
from pytimbr_api import timbr_http_connector
|
|
4
6
|
from functools import wraps
|
|
7
|
+
from cryptography.fernet import Fernet
|
|
5
8
|
|
|
6
9
|
from ..config import cache_timeout, ignore_tags, ignore_tags_prefix
|
|
7
10
|
from .general import to_boolean
|
|
@@ -40,6 +43,42 @@ def _serialize_cache_key(*args, **kwargs):
|
|
|
40
43
|
return (tuple(serialize(arg) for arg in args), tuple((k, serialize(v)) for k, v in kwargs.items()))
|
|
41
44
|
|
|
42
45
|
|
|
46
|
+
def generate_key() -> bytes:
|
|
47
|
+
"""Generate a new Fernet secret key."""
|
|
48
|
+
passcode = b"lucylit2025"
|
|
49
|
+
hlib = hashlib.md5()
|
|
50
|
+
hlib.update(passcode)
|
|
51
|
+
return base64.urlsafe_b64encode(hlib.hexdigest().encode('utf-8'))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
ENCRYPT_KEY = generate_key()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def encrypt_prompt(prompt: Any, key: Optional[bytes] = ENCRYPT_KEY) -> bytes:
|
|
58
|
+
"""Serialize & encrypt the prompt; returns a URL-safe token."""
|
|
59
|
+
if isinstance(prompt, str):
|
|
60
|
+
text = prompt
|
|
61
|
+
elif isinstance(prompt, list):
|
|
62
|
+
parts = []
|
|
63
|
+
for message in prompt:
|
|
64
|
+
if hasattr(message, "content"):
|
|
65
|
+
parts.append(f"{message.type}: {message.content}")
|
|
66
|
+
else:
|
|
67
|
+
parts.append(str(message))
|
|
68
|
+
text = "\n".join(parts)
|
|
69
|
+
else:
|
|
70
|
+
text = str(prompt)
|
|
71
|
+
|
|
72
|
+
f = Fernet(key)
|
|
73
|
+
return f.encrypt(text.encode()).decode('utf-8')
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def decrypt_prompt(token: bytes, key: bytes) -> str:
|
|
77
|
+
"""Decrypt the token and return the original prompt string."""
|
|
78
|
+
f = Fernet(key)
|
|
79
|
+
return f.decrypt(token).decode()
|
|
80
|
+
|
|
81
|
+
|
|
43
82
|
def cache_with_version_check(func):
|
|
44
83
|
"""Decorator to cache function results and invalidate if ontology version changes."""
|
|
45
84
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-timbr
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.7
|
|
4
4
|
Summary: LangChain & LangGraph extensions that parse LLM prompts into Timbr semantic SQL and execute them.
|
|
5
5
|
Project-URL: Homepage, https://github.com/WPSemantix/langchain-timbr
|
|
6
6
|
Project-URL: Documentation, https://docs.timbr.ai/doc/docs/integration/langchain-sdk/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
langchain_timbr/__init__.py,sha256=qNyk3Rt-8oWr_OGuU_E-6siNZXuCnvVEkj65EIuVbbQ,824
|
|
2
|
+
langchain_timbr/_version.py,sha256=MO-pKnEzeW3zl7_c60hrWWrquNyRCaWfqqY8EMXwxVA,704
|
|
3
|
+
langchain_timbr/config.py,sha256=c3A_HIw1b1Y6tc4EaXHZRJ_OptGLzl5bQGzx4ec_tgM,1605
|
|
4
|
+
langchain_timbr/timbr_llm_connector.py,sha256=mdkWskpvmXZre5AzVFn6KfPnVH5YN5MIwfEoXWBLMgY,13170
|
|
5
|
+
langchain_timbr/langchain/__init__.py,sha256=ejcsZKP9PK0j4WrrCCcvBXpDpP-TeRiVb21OIUJqix8,580
|
|
6
|
+
langchain_timbr/langchain/execute_timbr_query_chain.py,sha256=snfx22QE0hM3pjvoApUBFGvtIqNt2Yy1PFnx4uuRScs,16316
|
|
7
|
+
langchain_timbr/langchain/generate_answer_chain.py,sha256=nteA4QZp9CAOskTBl_CokwaMlqnR2g2GvKz2mLs9WVY,4871
|
|
8
|
+
langchain_timbr/langchain/generate_timbr_sql_chain.py,sha256=G2uEPB4NbZcDIkWtoxVlPNcuaaUcEmUcP39_4U5aYK0,9811
|
|
9
|
+
langchain_timbr/langchain/identify_concept_chain.py,sha256=kuzg0jJQpFGIiaxtNhdQ5K4HXveLVwONFNsoipPCteE,7169
|
|
10
|
+
langchain_timbr/langchain/timbr_sql_agent.py,sha256=fCYAYjvE_9xVtp-xicOGKRbvtjK8gRipXkSl9mKTcio,20810
|
|
11
|
+
langchain_timbr/langchain/validate_timbr_sql_chain.py,sha256=rq3fVmNyt_D1vfRbvn21f_lACSqPiHdVMri4Gofw5nY,10264
|
|
12
|
+
langchain_timbr/langgraph/__init__.py,sha256=mKBFd0x01jWpRujUWe-suX3FFhenPoDxrvzs8I0mum0,457
|
|
13
|
+
langchain_timbr/langgraph/execute_timbr_query_node.py,sha256=Tz7N3tCGJgot7v23SxYZaoG2o0kxXanv0wLcT1pJwyc,5994
|
|
14
|
+
langchain_timbr/langgraph/generate_response_node.py,sha256=opwscNEXabaSyCFLbzGQFkDFEymJurhNU9aAtm1rnOk,2375
|
|
15
|
+
langchain_timbr/langgraph/generate_timbr_sql_node.py,sha256=kd_soT3w3V0fGDI52R_iL0S1jlTApUawWxRJFQ6yo_Q,5370
|
|
16
|
+
langchain_timbr/langgraph/identify_concept_node.py,sha256=aiLDFEcz_vM4zZ_ULe1SvJKmI-e4Fb2SibZQaEPz_eY,3649
|
|
17
|
+
langchain_timbr/langgraph/validate_timbr_query_node.py,sha256=utdy8cj3Pe6cd3OSAUjpCh7gwQI8EaenUW7bmptC7iQ,5191
|
|
18
|
+
langchain_timbr/llm_wrapper/llm_wrapper.py,sha256=j94DqIGECXyfAVayLC7VaNxs_8n1qYFiHY2Qvt2B3Bc,17537
|
|
19
|
+
langchain_timbr/llm_wrapper/timbr_llm_wrapper.py,sha256=sDqDOz0qu8b4WWlagjNceswMVyvEJ8yBWZq2etBh-T0,1362
|
|
20
|
+
langchain_timbr/utils/general.py,sha256=KkehHvIj8GoQ_0KVXLcUVeaYaTtkuzgXmYYx2TXJhI4,10253
|
|
21
|
+
langchain_timbr/utils/prompt_service.py,sha256=QVmfA9cHO2IPVsKG8V5cuMm2gPfvRq2VzLcx04sqT88,12197
|
|
22
|
+
langchain_timbr/utils/temperature_supported_models.json,sha256=d3UmBUpG38zDjjB42IoGpHTUaf0pHMBRSPY99ao1a3g,1832
|
|
23
|
+
langchain_timbr/utils/timbr_llm_utils.py,sha256=7jg5TxTMkdLKZPvGbS49bTSmX6z8gbP84iKb_JALTy8,34646
|
|
24
|
+
langchain_timbr/utils/timbr_utils.py,sha256=x-z46NQn8nhRR8PJ5l23uh0qEpDWbhD8x4r-DyY4IYY,18864
|
|
25
|
+
langchain_timbr-2.1.7.dist-info/METADATA,sha256=aV12qFam0Klb2tGTr5we4lb9PzFRQFEEMsOZ0wcMYgQ,10724
|
|
26
|
+
langchain_timbr-2.1.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
27
|
+
langchain_timbr-2.1.7.dist-info/licenses/LICENSE,sha256=0ITGFk2alkC7-e--bRGtuzDrv62USIiVyV2Crf3_L_0,1065
|
|
28
|
+
langchain_timbr-2.1.7.dist-info/RECORD,,
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
langchain_timbr/__init__.py,sha256=gxd6Y6QDmYZtPlYVdXtPIy501hMOZXHjWh2qq4qzt_s,828
|
|
2
|
-
langchain_timbr/_version.py,sha256=EwjLAOHxpsOZpfhlwgV2gSqwFh_1AQNnM-WrOk4-4zg,704
|
|
3
|
-
langchain_timbr/config.py,sha256=CdDuUKbI_sdjNkGVk_QEmeqQHjFlJjBY1VI19JuBG2o,1601
|
|
4
|
-
langchain_timbr/timbr_llm_connector.py,sha256=mdkWskpvmXZre5AzVFn6KfPnVH5YN5MIwfEoXWBLMgY,13170
|
|
5
|
-
langchain_timbr/langchain/__init__.py,sha256=ejcsZKP9PK0j4WrrCCcvBXpDpP-TeRiVb21OIUJqix8,580
|
|
6
|
-
langchain_timbr/langchain/execute_timbr_query_chain.py,sha256=6USOkCJih0yGk7PgYW_zTHJfip4DpFcvkD-VhI2dMp0,16302
|
|
7
|
-
langchain_timbr/langchain/generate_answer_chain.py,sha256=nteA4QZp9CAOskTBl_CokwaMlqnR2g2GvKz2mLs9WVY,4871
|
|
8
|
-
langchain_timbr/langchain/generate_timbr_sql_chain.py,sha256=XmEkEU4q8t66GJZE-pWAAWqYYFFfv9ej6DzjRiTVNRw,9797
|
|
9
|
-
langchain_timbr/langchain/identify_concept_chain.py,sha256=kuzg0jJQpFGIiaxtNhdQ5K4HXveLVwONFNsoipPCteE,7169
|
|
10
|
-
langchain_timbr/langchain/timbr_sql_agent.py,sha256=tIcr2SCSb5LnOA3zreZbzOvVgR8e2NFv4HaLVcLUNCg,20790
|
|
11
|
-
langchain_timbr/langchain/validate_timbr_sql_chain.py,sha256=OcE_7yfb9xpD-I4OS7RG1bY4-yi1UicjvGegOv_vkQU,9567
|
|
12
|
-
langchain_timbr/langgraph/__init__.py,sha256=mKBFd0x01jWpRujUWe-suX3FFhenPoDxrvzs8I0mum0,457
|
|
13
|
-
langchain_timbr/langgraph/execute_timbr_query_node.py,sha256=UddbYiQya_-QlZm-QdImxpvzfiNiRDHyiLAHdpTEzXc,5984
|
|
14
|
-
langchain_timbr/langgraph/generate_response_node.py,sha256=opwscNEXabaSyCFLbzGQFkDFEymJurhNU9aAtm1rnOk,2375
|
|
15
|
-
langchain_timbr/langgraph/generate_timbr_sql_node.py,sha256=TekD9D0rM4aKuzS50Kzwkbshei5NHbTTVTXUC41dnyU,5360
|
|
16
|
-
langchain_timbr/langgraph/identify_concept_node.py,sha256=aiLDFEcz_vM4zZ_ULe1SvJKmI-e4Fb2SibZQaEPz_eY,3649
|
|
17
|
-
langchain_timbr/langgraph/validate_timbr_query_node.py,sha256=-2fuieCz1hv6ua-17zfonme8LQ_OoPnoOBTdGSXkJgs,4793
|
|
18
|
-
langchain_timbr/llm_wrapper/llm_wrapper.py,sha256=j94DqIGECXyfAVayLC7VaNxs_8n1qYFiHY2Qvt2B3Bc,17537
|
|
19
|
-
langchain_timbr/llm_wrapper/timbr_llm_wrapper.py,sha256=sDqDOz0qu8b4WWlagjNceswMVyvEJ8yBWZq2etBh-T0,1362
|
|
20
|
-
langchain_timbr/utils/general.py,sha256=KkehHvIj8GoQ_0KVXLcUVeaYaTtkuzgXmYYx2TXJhI4,10253
|
|
21
|
-
langchain_timbr/utils/prompt_service.py,sha256=QT7kiq72rQno77z1-tvGGD7HlH_wdTQAl_1teSoKEv4,11373
|
|
22
|
-
langchain_timbr/utils/temperature_supported_models.json,sha256=d3UmBUpG38zDjjB42IoGpHTUaf0pHMBRSPY99ao1a3g,1832
|
|
23
|
-
langchain_timbr/utils/timbr_llm_utils.py,sha256=6CHCwMHOPZtLjxh49a4UoxGxgTmuOUO3R8sJMHsGKxI,34970
|
|
24
|
-
langchain_timbr/utils/timbr_utils.py,sha256=SvmQ0wYicODNhmo8c-5_KPDBAfrBVBkUfoO8sPItQhk,17759
|
|
25
|
-
langchain_timbr-2.1.6.dist-info/METADATA,sha256=imT7XLtey6gdk7WJlp6ZcYnndjCE6hAJ6QPzQmgcyJo,10724
|
|
26
|
-
langchain_timbr-2.1.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
27
|
-
langchain_timbr-2.1.6.dist-info/licenses/LICENSE,sha256=0ITGFk2alkC7-e--bRGtuzDrv62USIiVyV2Crf3_L_0,1065
|
|
28
|
-
langchain_timbr-2.1.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|