langchain-timbr 2.1.14__tar.gz → 3.0.0__tar.gz
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-2.1.14 → langchain_timbr-3.0.0}/PKG-INFO +1 -1
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/_version.py +2 -2
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/execute_timbr_query_chain.py +62 -19
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/generate_answer_chain.py +18 -4
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/generate_timbr_sql_chain.py +54 -17
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/identify_concept_chain.py +31 -9
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/timbr_sql_agent.py +20 -1
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/validate_timbr_sql_chain.py +57 -17
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langgraph/execute_timbr_query_node.py +3 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langgraph/generate_response_node.py +5 -2
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langgraph/generate_timbr_sql_node.py +3 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langgraph/identify_concept_node.py +3 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langgraph/validate_timbr_query_node.py +3 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/utils/timbr_llm_utils.py +333 -166
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/utils/timbr_utils.py +27 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/conftest.py +1 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_agent_integration.py +56 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_langchain_chains.py +7 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/.github/dependabot.yml +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/.github/pull_request_template.md +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/.github/workflows/_codespell.yml +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/.github/workflows/_fossa.yml +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/.github/workflows/install-dependencies-and-run-tests.yml +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/.github/workflows/publish.yml +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/.gitignore +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/LICENSE +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/README.md +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/SECURITY.md +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/pyproject.toml +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/pytest.ini +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/requirements.txt +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/requirements310.txt +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/requirements311.txt +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/__init__.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/config.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/__init__.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langgraph/__init__.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/llm_wrapper/llm_wrapper.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/llm_wrapper/timbr_llm_wrapper.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/timbr_llm_connector.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/utils/general.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/utils/prompt_service.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/utils/temperature_supported_models.json +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/README.md +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_azure_databricks_provider.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_azure_openai_model.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_chain_pipeline.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_chain_reasoning.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_jwt_token.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_langgraph_nodes.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/integration/test_timeout_functionality.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/standard/conftest.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/standard/test_chain_documentation.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/standard/test_connection_validation.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/standard/test_llm_wrapper_optional_params.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/standard/test_optional_llm_integration.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/standard/test_standard_chain_requirements.py +0 -0
- {langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/tests/standard/test_unit_tests.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langchain-timbr
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
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/
|
|
@@ -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 = '
|
|
32
|
-
__version_tuple__ = version_tuple = (
|
|
31
|
+
__version__ = version = '3.0.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (3, 0, 0)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -2,6 +2,8 @@ from typing import Optional, Union, Dict, Any
|
|
|
2
2
|
from langchain.chains.base import Chain
|
|
3
3
|
from langchain.llms.base import LLM
|
|
4
4
|
|
|
5
|
+
from langchain_timbr.utils.timbr_utils import get_timbr_agent_options
|
|
6
|
+
|
|
5
7
|
from ..utils.general import parse_list, to_boolean, to_integer, validate_timbr_connection_params
|
|
6
8
|
from ..utils.timbr_utils import run_query, validate_sql
|
|
7
9
|
from ..utils.timbr_llm_utils import generate_sql
|
|
@@ -16,6 +18,8 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
16
18
|
returns the query results, handling retries and result validation. It uses an LLM
|
|
17
19
|
for query generation and connects to Timbr via URL and token.
|
|
18
20
|
"""
|
|
21
|
+
|
|
22
|
+
_ontology: Optional[str] = None
|
|
19
23
|
|
|
20
24
|
def __init__(
|
|
21
25
|
self,
|
|
@@ -38,6 +42,7 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
38
42
|
note: Optional[str] = '',
|
|
39
43
|
db_is_case_sensitive: Optional[bool] = False,
|
|
40
44
|
graph_depth: Optional[int] = 1,
|
|
45
|
+
agent: Optional[str] = None,
|
|
41
46
|
verify_ssl: Optional[bool] = True,
|
|
42
47
|
is_jwt: Optional[bool] = False,
|
|
43
48
|
jwt_tenant_id: Optional[str] = None,
|
|
@@ -67,6 +72,7 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
67
72
|
:param note: Optional additional note to extend our llm prompt
|
|
68
73
|
:param db_is_case_sensitive: Whether the database is case sensitive (default is False).
|
|
69
74
|
:param graph_depth: Maximum number of relationship hops to traverse from the source concept during schema exploration (default is 1).
|
|
75
|
+
:param agent: Optional Timbr agent name for options setup.
|
|
70
76
|
:param verify_ssl: Whether to verify SSL certificates (default is True).
|
|
71
77
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
72
78
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
@@ -116,33 +122,64 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
116
122
|
|
|
117
123
|
self._url = url if url is not None else config.url
|
|
118
124
|
self._token = token if token is not None else config.token
|
|
119
|
-
self._ontology = ontology if ontology is not None else config.ontology
|
|
120
125
|
|
|
121
126
|
# Validate required parameters
|
|
122
127
|
validate_timbr_connection_params(self._url, self._token)
|
|
123
128
|
|
|
124
|
-
self._schema = schema
|
|
125
|
-
self._concept = concept
|
|
126
|
-
self._concepts_list = parse_list(concepts_list)
|
|
127
|
-
self._views_list = parse_list(views_list)
|
|
128
|
-
self._include_tags = parse_list(include_tags)
|
|
129
|
-
self._include_logic_concepts = to_boolean(include_logic_concepts)
|
|
130
|
-
self._exclude_properties = parse_list(exclude_properties)
|
|
131
|
-
self._should_validate_sql = to_boolean(should_validate_sql)
|
|
132
|
-
self._retries = to_integer(retries)
|
|
133
|
-
self._max_limit = to_integer(max_limit)
|
|
134
|
-
self._retry_if_no_results = to_boolean(retry_if_no_results)
|
|
135
|
-
self._no_results_max_retries = to_integer(no_results_max_retries)
|
|
136
|
-
self._note = note
|
|
137
|
-
self._db_is_case_sensitive = to_boolean(db_is_case_sensitive)
|
|
138
|
-
self._graph_depth = to_integer(graph_depth)
|
|
139
129
|
self._verify_ssl = to_boolean(verify_ssl)
|
|
140
130
|
self._is_jwt = to_boolean(is_jwt)
|
|
141
131
|
self._jwt_tenant_id = jwt_tenant_id
|
|
142
132
|
self._debug = to_boolean(debug)
|
|
143
133
|
self._conn_params = conn_params or {}
|
|
144
|
-
self.
|
|
145
|
-
|
|
134
|
+
self._max_limit = config.llm_default_limit # use default value so the self._get_conn_params() won't fail before agent options are processed
|
|
135
|
+
|
|
136
|
+
self._agent = agent
|
|
137
|
+
if self._agent:
|
|
138
|
+
agent_options = get_timbr_agent_options(self._agent, conn_params=self._get_conn_params())
|
|
139
|
+
|
|
140
|
+
self._ontology = agent_options.get("ontology") if "ontology" in agent_options else None
|
|
141
|
+
self._schema = agent_options.get("schema") if "schema" in agent_options else schema
|
|
142
|
+
self._concept = agent_options.get("concept") if "concept" in agent_options else None
|
|
143
|
+
self._concepts_list = parse_list(agent_options.get("concepts_list")) if "concepts_list" in agent_options else None
|
|
144
|
+
self._views_list = parse_list(agent_options.get("views_list")) if "views_list" in agent_options else None
|
|
145
|
+
self._include_tags = parse_list(agent_options.get("include_tags")) if "include_tags" in agent_options else None
|
|
146
|
+
self._include_logic_concepts = to_boolean(agent_options.get("include_logic_concepts")) if "include_logic_concepts" in agent_options else False
|
|
147
|
+
self._exclude_properties = parse_list(agent_options.get("exclude_properties")) if "exclude_properties" in agent_options else ['entity_id', 'entity_type', 'entity_label']
|
|
148
|
+
self._should_validate_sql = to_boolean(agent_options.get("should_validate_sql")) if "should_validate_sql" in agent_options else config.should_validate_sql
|
|
149
|
+
self._retries = to_integer(agent_options.get("retries") if "retries" in agent_options else retries)
|
|
150
|
+
self._max_limit = to_integer(agent_options.get("max_limit")) if "max_limit" in agent_options else config.llm_default_limit
|
|
151
|
+
self._retry_if_no_results = to_boolean(agent_options.get("retry_if_no_results")) if "retry_if_no_results" in agent_options else config.retry_if_no_results
|
|
152
|
+
self._no_results_max_retries = to_integer(agent_options.get("no_results_max_retries")) if "no_results_max_retries" in agent_options else 2
|
|
153
|
+
self._db_is_case_sensitive = to_boolean(agent_options.get("db_is_case_sensitive")) if "db_is_case_sensitive" in agent_options else False
|
|
154
|
+
self._graph_depth = to_integer(agent_options.get("graph_depth")) if "graph_depth" in agent_options else 1
|
|
155
|
+
self._note = agent_options.get("note") if "note" in agent_options else ''
|
|
156
|
+
if note:
|
|
157
|
+
self._note = ((self._note + '\n') if self._note else '') + note
|
|
158
|
+
self._enable_reasoning = to_boolean(agent_options.get("enable_reasoning")) if "enable_reasoning" in agent_options else config.enable_reasoning
|
|
159
|
+
if enable_reasoning is not None and enable_reasoning != self._enable_reasoning:
|
|
160
|
+
self._enable_reasoning = to_boolean(enable_reasoning)
|
|
161
|
+
self._reasoning_steps = to_integer(agent_options.get("reasoning_steps")) if "reasoning_steps" in agent_options else config.reasoning_steps
|
|
162
|
+
if reasoning_steps is not None and reasoning_steps != self._reasoning_steps:
|
|
163
|
+
self._reasoning_steps = to_integer(reasoning_steps)
|
|
164
|
+
else:
|
|
165
|
+
self._ontology = ontology if ontology is not None else config.ontology
|
|
166
|
+
self._schema = schema
|
|
167
|
+
self._concept = concept
|
|
168
|
+
self._concepts_list = parse_list(concepts_list)
|
|
169
|
+
self._views_list = parse_list(views_list)
|
|
170
|
+
self._include_tags = parse_list(include_tags)
|
|
171
|
+
self._include_logic_concepts = to_boolean(include_logic_concepts)
|
|
172
|
+
self._exclude_properties = parse_list(exclude_properties)
|
|
173
|
+
self._should_validate_sql = to_boolean(should_validate_sql)
|
|
174
|
+
self._retries = to_integer(retries)
|
|
175
|
+
self._max_limit = to_integer(max_limit)
|
|
176
|
+
self._retry_if_no_results = to_boolean(retry_if_no_results)
|
|
177
|
+
self._no_results_max_retries = to_integer(no_results_max_retries)
|
|
178
|
+
self._db_is_case_sensitive = to_boolean(db_is_case_sensitive)
|
|
179
|
+
self._graph_depth = to_integer(graph_depth)
|
|
180
|
+
self._note = note
|
|
181
|
+
self._enable_reasoning = to_boolean(enable_reasoning)
|
|
182
|
+
self._reasoning_steps = to_integer(reasoning_steps)
|
|
146
183
|
|
|
147
184
|
|
|
148
185
|
@property
|
|
@@ -171,7 +208,7 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
171
208
|
return {
|
|
172
209
|
"url": self._url,
|
|
173
210
|
"token": self._token,
|
|
174
|
-
"ontology": self._ontology,
|
|
211
|
+
"ontology": self._ontology if self._ontology is not None else config.ontology,
|
|
175
212
|
"verify_ssl": self._verify_ssl,
|
|
176
213
|
"is_jwt": self._is_jwt,
|
|
177
214
|
"jwt_tenant_id": self._jwt_tenant_id,
|
|
@@ -247,6 +284,8 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
247
284
|
concept_name = inputs.get("concept", self._concept)
|
|
248
285
|
is_sql_valid = True
|
|
249
286
|
error = None
|
|
287
|
+
identify_concept_reason = None
|
|
288
|
+
generate_sql_reason = None
|
|
250
289
|
reasoning_status = None
|
|
251
290
|
rows = []
|
|
252
291
|
usage_metadata = {}
|
|
@@ -270,6 +309,8 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
270
309
|
is_sql_valid = True
|
|
271
310
|
|
|
272
311
|
error = generate_res.get("error")
|
|
312
|
+
identify_concept_reason = generate_res.get("identify_concept_reason")
|
|
313
|
+
generate_sql_reason = generate_res.get("generate_sql_reason")
|
|
273
314
|
usage_metadata = self._summarize_usage_metadata(usage_metadata, generate_res.get("usage_metadata", {}))
|
|
274
315
|
|
|
275
316
|
is_sql_not_tried = not any(sql.lower().strip() == gen.lower().strip() for gen in generated)
|
|
@@ -305,6 +346,8 @@ class ExecuteTimbrQueryChain(Chain):
|
|
|
305
346
|
"concept": concept_name,
|
|
306
347
|
"error": error if not is_sql_valid else None,
|
|
307
348
|
"reasoning_status": reasoning_status,
|
|
349
|
+
"identify_concept_reason": identify_concept_reason,
|
|
350
|
+
"generate_sql_reason": generate_sql_reason,
|
|
308
351
|
self.usage_metadata_key: usage_metadata,
|
|
309
352
|
}
|
|
310
353
|
|
|
@@ -2,6 +2,8 @@ from typing import Optional, Dict, Any
|
|
|
2
2
|
from langchain.chains.base import Chain
|
|
3
3
|
from langchain.llms.base import LLM
|
|
4
4
|
|
|
5
|
+
from langchain_timbr.utils.timbr_utils import get_timbr_agent_options
|
|
6
|
+
|
|
5
7
|
from ..utils.general import to_boolean, validate_timbr_connection_params
|
|
6
8
|
from ..utils.timbr_llm_utils import answer_question
|
|
7
9
|
from ..llm_wrapper.llm_wrapper import LlmWrapper
|
|
@@ -19,11 +21,12 @@ class GenerateAnswerChain(Chain):
|
|
|
19
21
|
llm: Optional[LLM] = None,
|
|
20
22
|
url: Optional[str] = None,
|
|
21
23
|
token: Optional[str] = None,
|
|
24
|
+
note: Optional[str] = '',
|
|
25
|
+
agent: Optional[str] = None,
|
|
22
26
|
verify_ssl: Optional[bool] = True,
|
|
23
27
|
is_jwt: Optional[bool] = False,
|
|
24
28
|
jwt_tenant_id: Optional[str] = None,
|
|
25
29
|
conn_params: Optional[dict] = None,
|
|
26
|
-
note: Optional[str] = '',
|
|
27
30
|
debug: Optional[bool] = False,
|
|
28
31
|
**kwargs,
|
|
29
32
|
):
|
|
@@ -31,11 +34,12 @@ class GenerateAnswerChain(Chain):
|
|
|
31
34
|
:param llm: An LLM instance or a function that takes a prompt string and returns the LLM’s response (optional, will use LlmWrapper with env variables if not provided)
|
|
32
35
|
:param url: Timbr server url (optional, defaults to TIMBR_URL environment variable)
|
|
33
36
|
:param token: Timbr password or token value (optional, defaults to TIMBR_TOKEN environment variable)
|
|
37
|
+
:param note: Optional additional note to extend our llm prompt
|
|
38
|
+
:param agent: Optional Timbr agent name for options setup.
|
|
34
39
|
:param verify_ssl: Whether to verify SSL certificates (default is True).
|
|
35
40
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
36
41
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
37
42
|
:param conn_params: Extra Timbr connection parameters sent with every request (e.g., 'x-api-impersonate-user').
|
|
38
|
-
:param note: Optional additional note to extend our llm prompt
|
|
39
43
|
|
|
40
44
|
## Example
|
|
41
45
|
```
|
|
@@ -79,7 +83,17 @@ class GenerateAnswerChain(Chain):
|
|
|
79
83
|
self._jwt_tenant_id = jwt_tenant_id
|
|
80
84
|
self._debug = to_boolean(debug)
|
|
81
85
|
self._conn_params = conn_params or {}
|
|
82
|
-
|
|
86
|
+
|
|
87
|
+
self._agent = agent
|
|
88
|
+
if self._agent:
|
|
89
|
+
agent_options = get_timbr_agent_options(self._agent, conn_params=self._get_conn_params())
|
|
90
|
+
|
|
91
|
+
self._note = agent_options.get("note") if "note" in agent_options else ''
|
|
92
|
+
if note:
|
|
93
|
+
self._note = ((self._note + '\n') if self._note else '') + note
|
|
94
|
+
|
|
95
|
+
else:
|
|
96
|
+
self._note = note
|
|
83
97
|
|
|
84
98
|
|
|
85
99
|
@property
|
|
@@ -100,7 +114,7 @@ class GenerateAnswerChain(Chain):
|
|
|
100
114
|
return {
|
|
101
115
|
"url": self._url,
|
|
102
116
|
"token": self._token,
|
|
103
|
-
|
|
117
|
+
"ontology": config.ontology,
|
|
104
118
|
"verify_ssl": self._verify_ssl,
|
|
105
119
|
"is_jwt": self._is_jwt,
|
|
106
120
|
"jwt_tenant_id": self._jwt_tenant_id,
|
|
@@ -2,6 +2,8 @@ from typing import Optional, Union, Dict, Any
|
|
|
2
2
|
from langchain.chains.base import Chain
|
|
3
3
|
from langchain.llms.base import LLM
|
|
4
4
|
|
|
5
|
+
from langchain_timbr.utils.timbr_utils import get_timbr_agent_options
|
|
6
|
+
|
|
5
7
|
from ..utils.general import parse_list, to_boolean, to_integer, validate_timbr_connection_params
|
|
6
8
|
from ..utils.timbr_llm_utils import generate_sql
|
|
7
9
|
from ..llm_wrapper.llm_wrapper import LlmWrapper
|
|
@@ -15,6 +17,8 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
15
17
|
against Timbr ontology/knowledge graph databases. It uses an LLM to process prompts and
|
|
16
18
|
connects to Timbr via URL and token for SQL generation.
|
|
17
19
|
"""
|
|
20
|
+
|
|
21
|
+
_ontology: Optional[str] = None
|
|
18
22
|
|
|
19
23
|
def __init__(
|
|
20
24
|
self,
|
|
@@ -35,6 +39,7 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
35
39
|
note: Optional[str] = '',
|
|
36
40
|
db_is_case_sensitive: Optional[bool] = False,
|
|
37
41
|
graph_depth: Optional[int] = 1,
|
|
42
|
+
agent: Optional[str] = None,
|
|
38
43
|
verify_ssl: Optional[bool] = True,
|
|
39
44
|
is_jwt: Optional[bool] = False,
|
|
40
45
|
jwt_tenant_id: Optional[str] = None,
|
|
@@ -62,6 +67,7 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
62
67
|
:param note: Optional additional note to extend our llm prompt
|
|
63
68
|
:param db_is_case_sensitive: Whether the database is case sensitive (default is False).
|
|
64
69
|
:param graph_depth: Maximum number of relationship hops to traverse from the source concept during schema exploration (default is 1).
|
|
70
|
+
:param agent: Optional Timbr agent name for options setup.
|
|
65
71
|
:param verify_ssl: Whether to verify SSL certificates (default is True).
|
|
66
72
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
67
73
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
@@ -111,31 +117,60 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
111
117
|
|
|
112
118
|
self._url = url if url is not None else config.url
|
|
113
119
|
self._token = token if token is not None else config.token
|
|
114
|
-
self._ontology = ontology if ontology is not None else config.ontology
|
|
115
120
|
|
|
116
121
|
# Validate required parameters
|
|
117
122
|
validate_timbr_connection_params(self._url, self._token)
|
|
118
123
|
|
|
119
|
-
self._schema = schema
|
|
120
|
-
self._concept = concept
|
|
121
|
-
self._concepts_list = parse_list(concepts_list)
|
|
122
|
-
self._views_list = parse_list(views_list)
|
|
123
|
-
self._include_tags = parse_list(include_tags)
|
|
124
|
-
self._include_logic_concepts = to_boolean(include_logic_concepts)
|
|
125
|
-
self._should_validate_sql = to_boolean(should_validate_sql)
|
|
126
|
-
self._exclude_properties = parse_list(exclude_properties)
|
|
127
|
-
self._retries = to_integer(retries)
|
|
128
|
-
self._max_limit = to_integer(max_limit)
|
|
129
|
-
self._note = note
|
|
130
|
-
self._db_is_case_sensitive = to_boolean(db_is_case_sensitive)
|
|
131
|
-
self._graph_depth = to_integer(graph_depth)
|
|
132
124
|
self._verify_ssl = to_boolean(verify_ssl)
|
|
133
125
|
self._is_jwt = to_boolean(is_jwt)
|
|
134
126
|
self._jwt_tenant_id = jwt_tenant_id
|
|
135
127
|
self._debug = to_boolean(debug)
|
|
136
128
|
self._conn_params = conn_params or {}
|
|
137
|
-
self.
|
|
138
|
-
|
|
129
|
+
self._max_limit = config.llm_default_limit # use default value so the self._get_conn_params() won't fail before agent options are processed
|
|
130
|
+
|
|
131
|
+
self._agent = agent
|
|
132
|
+
if self._agent:
|
|
133
|
+
agent_options = get_timbr_agent_options(self._agent, conn_params=self._get_conn_params())
|
|
134
|
+
|
|
135
|
+
self._ontology = agent_options.get("ontology") if "ontology" in agent_options else None
|
|
136
|
+
self._schema = agent_options.get("schema") if "schema" in agent_options else schema
|
|
137
|
+
self._concept = agent_options.get("concept") if "concept" in agent_options else None
|
|
138
|
+
self._concepts_list = parse_list(agent_options.get("concepts_list")) if "concepts_list" in agent_options else None
|
|
139
|
+
self._views_list = parse_list(agent_options.get("views_list")) if "views_list" in agent_options else None
|
|
140
|
+
self._include_tags = parse_list(agent_options.get("include_tags")) if "include_tags" in agent_options else None
|
|
141
|
+
self._include_logic_concepts = to_boolean(agent_options.get("include_logic_concepts")) if "include_logic_concepts" in agent_options else False
|
|
142
|
+
self._exclude_properties = parse_list(agent_options.get("exclude_properties")) if "exclude_properties" in agent_options else ['entity_id', 'entity_type', 'entity_label']
|
|
143
|
+
self._should_validate_sql = to_boolean(agent_options.get("should_validate_sql")) if "should_validate_sql" in agent_options else config.should_validate_sql
|
|
144
|
+
self._retries = to_integer(agent_options.get("retries") if "retries" in agent_options else retries)
|
|
145
|
+
self._max_limit = to_integer(agent_options.get("max_limit")) if "max_limit" in agent_options else config.llm_default_limit
|
|
146
|
+
self._db_is_case_sensitive = to_boolean(agent_options.get("db_is_case_sensitive")) if "db_is_case_sensitive" in agent_options else False
|
|
147
|
+
self._graph_depth = to_integer(agent_options.get("graph_depth")) if "graph_depth" in agent_options else 1
|
|
148
|
+
self._note = agent_options.get("note") if "note" in agent_options else ''
|
|
149
|
+
if note:
|
|
150
|
+
self._note = ((self._note + '\n') if self._note else '') + note
|
|
151
|
+
self._enable_reasoning = to_boolean(agent_options.get("enable_reasoning")) if "enable_reasoning" in agent_options else config.enable_reasoning
|
|
152
|
+
if enable_reasoning is not None and enable_reasoning != self._enable_reasoning:
|
|
153
|
+
self._enable_reasoning = to_boolean(enable_reasoning)
|
|
154
|
+
self._reasoning_steps = to_integer(agent_options.get("reasoning_steps")) if "reasoning_steps" in agent_options else config.reasoning_steps
|
|
155
|
+
if reasoning_steps is not None and reasoning_steps != self._reasoning_steps:
|
|
156
|
+
self._reasoning_steps = to_integer(reasoning_steps)
|
|
157
|
+
else:
|
|
158
|
+
self._ontology = ontology if ontology is not None else config.ontology
|
|
159
|
+
self._schema = schema
|
|
160
|
+
self._concept = concept
|
|
161
|
+
self._concepts_list = parse_list(concepts_list)
|
|
162
|
+
self._views_list = parse_list(views_list)
|
|
163
|
+
self._include_tags = parse_list(include_tags)
|
|
164
|
+
self._include_logic_concepts = to_boolean(include_logic_concepts)
|
|
165
|
+
self._exclude_properties = parse_list(exclude_properties)
|
|
166
|
+
self._should_validate_sql = to_boolean(should_validate_sql)
|
|
167
|
+
self._retries = to_integer(retries)
|
|
168
|
+
self._max_limit = to_integer(max_limit)
|
|
169
|
+
self._db_is_case_sensitive = to_boolean(db_is_case_sensitive)
|
|
170
|
+
self._graph_depth = to_integer(graph_depth)
|
|
171
|
+
self._enable_reasoning = to_boolean(enable_reasoning)
|
|
172
|
+
self._reasoning_steps = to_integer(reasoning_steps)
|
|
173
|
+
self._note = note
|
|
139
174
|
|
|
140
175
|
|
|
141
176
|
@property
|
|
@@ -163,7 +198,7 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
163
198
|
return {
|
|
164
199
|
"url": self._url,
|
|
165
200
|
"token": self._token,
|
|
166
|
-
"ontology": self._ontology,
|
|
201
|
+
"ontology": self._ontology if self._ontology is not None else config.ontology,
|
|
167
202
|
"verify_ssl": self._verify_ssl,
|
|
168
203
|
"is_jwt": self._is_jwt,
|
|
169
204
|
"jwt_tenant_id": self._jwt_tenant_id,
|
|
@@ -206,6 +241,8 @@ class GenerateTimbrSqlChain(Chain):
|
|
|
206
241
|
"concept": concept,
|
|
207
242
|
"is_sql_valid": generate_res.get("is_sql_valid"),
|
|
208
243
|
"error": generate_res.get("error"),
|
|
244
|
+
"identify_concept_reason": generate_res.get("identify_concept_reason"),
|
|
245
|
+
"generate_sql_reason": generate_res.get("generate_sql_reason"),
|
|
209
246
|
"reasoning_status": generate_res.get("reasoning_status"),
|
|
210
247
|
self.usage_metadata_key: generate_res.get("usage_metadata"),
|
|
211
248
|
}
|
|
@@ -2,6 +2,8 @@ from typing import Optional, Union, Dict, Any
|
|
|
2
2
|
from langchain.chains.base import Chain
|
|
3
3
|
from langchain.llms.base import LLM
|
|
4
4
|
|
|
5
|
+
from langchain_timbr.utils.timbr_utils import get_timbr_agent_options
|
|
6
|
+
|
|
5
7
|
from ..utils.general import parse_list, to_boolean, to_integer, validate_timbr_connection_params
|
|
6
8
|
from ..utils.timbr_llm_utils import determine_concept
|
|
7
9
|
from ..llm_wrapper.llm_wrapper import LlmWrapper
|
|
@@ -16,6 +18,8 @@ class IdentifyTimbrConceptChain(Chain):
|
|
|
16
18
|
within a Timbr ontology/knowledge graph that best matches the user's intent. It uses an LLM
|
|
17
19
|
to process prompts and connects to Timbr via URL and token for concept identification.
|
|
18
20
|
"""
|
|
21
|
+
|
|
22
|
+
_ontology: Optional[str] = None
|
|
19
23
|
|
|
20
24
|
def __init__(
|
|
21
25
|
self,
|
|
@@ -30,6 +34,7 @@ class IdentifyTimbrConceptChain(Chain):
|
|
|
30
34
|
should_validate: Optional[bool] = False,
|
|
31
35
|
retries: Optional[int] = 3,
|
|
32
36
|
note: Optional[str] = '',
|
|
37
|
+
agent: Optional[str] = None,
|
|
33
38
|
verify_ssl: Optional[bool] = True,
|
|
34
39
|
is_jwt: Optional[bool] = False,
|
|
35
40
|
jwt_tenant_id: Optional[str] = None,
|
|
@@ -49,6 +54,7 @@ class IdentifyTimbrConceptChain(Chain):
|
|
|
49
54
|
:param should_validate: Whether to validate the identified concept before returning it
|
|
50
55
|
:param retries: Number of retry attempts if the identified concept is invalid
|
|
51
56
|
:param note: Optional additional note to extend our llm prompt
|
|
57
|
+
:param agent: Optional Timbr agent name for options setup.
|
|
52
58
|
:param verify_ssl: Whether to verify SSL certificates (default is True).
|
|
53
59
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
54
60
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
@@ -93,24 +99,40 @@ class IdentifyTimbrConceptChain(Chain):
|
|
|
93
99
|
|
|
94
100
|
self._url = url if url is not None else config.url
|
|
95
101
|
self._token = token if token is not None else config.token
|
|
96
|
-
self._ontology = ontology if ontology is not None else config.ontology
|
|
97
102
|
|
|
98
103
|
# Validate required parameters
|
|
99
104
|
validate_timbr_connection_params(self._url, self._token)
|
|
100
105
|
|
|
101
|
-
self._concepts_list = parse_list(concepts_list)
|
|
102
|
-
self._views_list = parse_list(views_list)
|
|
103
|
-
self._include_logic_concepts = to_boolean(include_logic_concepts)
|
|
104
|
-
self._include_tags = parse_list(include_tags)
|
|
105
|
-
self._should_validate = to_boolean(should_validate)
|
|
106
|
-
self._retries = to_integer(retries)
|
|
107
|
-
self._note = note
|
|
108
106
|
self._verify_ssl = to_boolean(verify_ssl)
|
|
109
107
|
self._is_jwt = to_boolean(is_jwt)
|
|
110
108
|
self._jwt_tenant_id = jwt_tenant_id
|
|
111
109
|
self._debug = to_boolean(debug)
|
|
112
110
|
self._conn_params = conn_params or {}
|
|
113
111
|
|
|
112
|
+
self._agent = agent
|
|
113
|
+
if self._agent:
|
|
114
|
+
agent_options = get_timbr_agent_options(self._agent, conn_params=self._get_conn_params())
|
|
115
|
+
|
|
116
|
+
self._ontology = agent_options.get("ontology") if "ontology" in agent_options else None
|
|
117
|
+
self._concepts_list = parse_list(agent_options.get("concepts_list")) if "concepts_list" in agent_options else None
|
|
118
|
+
self._views_list = parse_list(agent_options.get("views_list")) if "views_list" in agent_options else None
|
|
119
|
+
self._include_logic_concepts = to_boolean(agent_options.get("include_logic_concepts")) if "include_logic_concepts" in agent_options else False
|
|
120
|
+
self._include_tags = parse_list(agent_options.get("include_tags")) if "include_tags" in agent_options else None
|
|
121
|
+
self._should_validate = to_boolean(agent_options.get("should_validate")) if "should_validate" in agent_options else False
|
|
122
|
+
self._retries = to_integer(agent_options.get("retries") if "retries" in agent_options else retries)
|
|
123
|
+
self._note = agent_options.get("note") if "note" in agent_options else ''
|
|
124
|
+
if note:
|
|
125
|
+
self._note = ((self._note + '\n') if self._note else '') + note
|
|
126
|
+
else:
|
|
127
|
+
self._ontology = ontology if ontology is not None else config.ontology
|
|
128
|
+
self._concepts_list = parse_list(concepts_list)
|
|
129
|
+
self._views_list = parse_list(views_list)
|
|
130
|
+
self._include_logic_concepts = to_boolean(include_logic_concepts)
|
|
131
|
+
self._include_tags = parse_list(include_tags)
|
|
132
|
+
self._should_validate = to_boolean(should_validate)
|
|
133
|
+
self._retries = to_integer(retries)
|
|
134
|
+
self._note = note
|
|
135
|
+
|
|
114
136
|
|
|
115
137
|
@property
|
|
116
138
|
def usage_metadata_key(self) -> str:
|
|
@@ -131,7 +153,7 @@ class IdentifyTimbrConceptChain(Chain):
|
|
|
131
153
|
return {
|
|
132
154
|
"url": self._url,
|
|
133
155
|
"token": self._token,
|
|
134
|
-
"ontology": self._ontology,
|
|
156
|
+
"ontology": self._ontology if self._ontology is not None else config.ontology,
|
|
135
157
|
"verify_ssl": self._verify_ssl,
|
|
136
158
|
"is_jwt": self._is_jwt,
|
|
137
159
|
"jwt_tenant_id": self._jwt_tenant_id,
|
{langchain_timbr-2.1.14 → langchain_timbr-3.0.0}/src/langchain_timbr/langchain/timbr_sql_agent.py
RENAMED
|
@@ -31,6 +31,7 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
31
31
|
note: Optional[str] = '',
|
|
32
32
|
db_is_case_sensitive: Optional[bool] = False,
|
|
33
33
|
graph_depth: Optional[int] = 1,
|
|
34
|
+
agent: Optional[str] = None,
|
|
34
35
|
verify_ssl: Optional[bool] = True,
|
|
35
36
|
is_jwt: Optional[bool] = False,
|
|
36
37
|
jwt_tenant_id: Optional[str] = None,
|
|
@@ -60,6 +61,7 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
60
61
|
:param note: Optional additional note to extend our llm prompt
|
|
61
62
|
:param db_is_case_sensitive: Whether the database is case sensitive (default is False).
|
|
62
63
|
:param graph_depth: Maximum number of relationship hops to traverse from the source concept during schema exploration (default is 1).
|
|
64
|
+
:param agent: Optional Timbr agent name for options setup.
|
|
63
65
|
:param verify_ssl: Whether to verify SSL certificates (default is True).
|
|
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).
|
|
@@ -114,6 +116,7 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
114
116
|
note=note,
|
|
115
117
|
db_is_case_sensitive=to_boolean(db_is_case_sensitive),
|
|
116
118
|
graph_depth=to_integer(graph_depth),
|
|
119
|
+
agent=agent,
|
|
117
120
|
verify_ssl=to_boolean(verify_ssl),
|
|
118
121
|
is_jwt=to_boolean(is_jwt),
|
|
119
122
|
jwt_tenant_id=jwt_tenant_id,
|
|
@@ -129,11 +132,12 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
129
132
|
llm=llm,
|
|
130
133
|
url=url,
|
|
131
134
|
token=token,
|
|
135
|
+
note=note,
|
|
136
|
+
agent=agent,
|
|
132
137
|
verify_ssl=to_boolean(verify_ssl),
|
|
133
138
|
is_jwt=to_boolean(is_jwt),
|
|
134
139
|
jwt_tenant_id=jwt_tenant_id,
|
|
135
140
|
conn_params=conn_params,
|
|
136
|
-
note=note,
|
|
137
141
|
debug=to_boolean(debug),
|
|
138
142
|
) if self._generate_answer else None
|
|
139
143
|
|
|
@@ -181,6 +185,8 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
181
185
|
"schema": None,
|
|
182
186
|
"concept": None,
|
|
183
187
|
"reasoning_status": None,
|
|
188
|
+
"identify_concept_reason": None,
|
|
189
|
+
"generate_sql_reason": None,
|
|
184
190
|
"usage_metadata": {},
|
|
185
191
|
},
|
|
186
192
|
log="Empty input received"
|
|
@@ -210,6 +216,8 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
210
216
|
"error": result.get("error", None),
|
|
211
217
|
"reasoning_status": result.get("reasoning_status", None),
|
|
212
218
|
"usage_metadata": usage_metadata,
|
|
219
|
+
"identify_concept_reason": None,
|
|
220
|
+
"generate_sql_reason": None,
|
|
213
221
|
},
|
|
214
222
|
log=f"Successfully executed query on concept: {result.get('concept', '')}"
|
|
215
223
|
)
|
|
@@ -224,6 +232,8 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
224
232
|
"schema": None,
|
|
225
233
|
"concept": None,
|
|
226
234
|
"reasoning_status": None,
|
|
235
|
+
"identify_concept_reason": None,
|
|
236
|
+
"generate_sql_reason": None,
|
|
227
237
|
"usage_metadata": {},
|
|
228
238
|
},
|
|
229
239
|
log=error_context
|
|
@@ -245,6 +255,8 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
245
255
|
"schema": None,
|
|
246
256
|
"concept": None,
|
|
247
257
|
"reasoning_status": None,
|
|
258
|
+
"identify_concept_reason": None,
|
|
259
|
+
"generate_sql_reason": None,
|
|
248
260
|
"usage_metadata": {},
|
|
249
261
|
},
|
|
250
262
|
log="Empty or whitespace-only input received"
|
|
@@ -286,6 +298,8 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
286
298
|
"concept": result.get("concept", ""),
|
|
287
299
|
"error": result.get("error", None),
|
|
288
300
|
"reasoning_status": result.get("reasoning_status", None),
|
|
301
|
+
"identify_concept_reason": result.get("identify_concept_reason", None),
|
|
302
|
+
"generate_sql_reason": result.get("generate_sql_reason", None),
|
|
289
303
|
"usage_metadata": usage_metadata,
|
|
290
304
|
},
|
|
291
305
|
log=f"Successfully executed query on concept: {result.get('concept', '')}"
|
|
@@ -301,6 +315,8 @@ class TimbrSqlAgent(BaseSingleActionAgent):
|
|
|
301
315
|
"schema": None,
|
|
302
316
|
"concept": None,
|
|
303
317
|
"reasoning_status": None,
|
|
318
|
+
"identify_concept_reason": None,
|
|
319
|
+
"generate_sql_reason": None,
|
|
304
320
|
"usage_metadata": {},
|
|
305
321
|
},
|
|
306
322
|
log=error_context
|
|
@@ -341,6 +357,7 @@ def create_timbr_sql_agent(
|
|
|
341
357
|
note: Optional[str] = '',
|
|
342
358
|
db_is_case_sensitive: Optional[bool] = False,
|
|
343
359
|
graph_depth: Optional[int] = 1,
|
|
360
|
+
agent: Optional[str] = None,
|
|
344
361
|
verify_ssl: Optional[bool] = True,
|
|
345
362
|
is_jwt: Optional[bool] = False,
|
|
346
363
|
jwt_tenant_id: Optional[str] = None,
|
|
@@ -372,6 +389,7 @@ def create_timbr_sql_agent(
|
|
|
372
389
|
:param note: Optional additional note to extend our llm prompt
|
|
373
390
|
:param db_is_case_sensitive: Whether the database is case sensitive (default is False).
|
|
374
391
|
:param graph_depth: Maximum number of relationship hops to traverse from the source concept during schema exploration (default is 1).
|
|
392
|
+
:param agent: Optional Timbr agent name for options setup.
|
|
375
393
|
:param verify_ssl: Whether to verify SSL certificates (default is True).
|
|
376
394
|
:param is_jwt: Whether to use JWT authentication (default is False).
|
|
377
395
|
:param jwt_tenant_id: JWT tenant ID for multi-tenant environments (required when is_jwt=True).
|
|
@@ -440,6 +458,7 @@ def create_timbr_sql_agent(
|
|
|
440
458
|
note=note,
|
|
441
459
|
db_is_case_sensitive=db_is_case_sensitive,
|
|
442
460
|
graph_depth=graph_depth,
|
|
461
|
+
agent=agent,
|
|
443
462
|
verify_ssl=verify_ssl,
|
|
444
463
|
is_jwt=is_jwt,
|
|
445
464
|
jwt_tenant_id=jwt_tenant_id,
|