datahub-agent-context 1.3.1.10rc1__py3-none-any.whl → 1.4.0rc2__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.
Files changed (42) hide show
  1. datahub_agent_context/__init__.py +11 -3
  2. datahub_agent_context/_version.py +1 -1
  3. datahub_agent_context/cli.py +152 -0
  4. datahub_agent_context/context.py +47 -34
  5. datahub_agent_context/langchain_tools/builder.py +6 -4
  6. datahub_agent_context/mcp_tools/base.py +6 -3
  7. datahub_agent_context/mcp_tools/save_document.py +634 -0
  8. datahub_agent_context/snowflake/__init__.py +0 -0
  9. datahub_agent_context/snowflake/generate_udfs.py +306 -0
  10. datahub_agent_context/snowflake/generators/__init__.py +21 -0
  11. datahub_agent_context/snowflake/generators/configuration.py +104 -0
  12. datahub_agent_context/snowflake/generators/cortex_agent.py +725 -0
  13. datahub_agent_context/snowflake/generators/network_rules.py +53 -0
  14. datahub_agent_context/snowflake/generators/stored_procedure.py +87 -0
  15. datahub_agent_context/snowflake/snowflake.py +662 -0
  16. datahub_agent_context/snowflake/udfs/__init__.py +1 -0
  17. datahub_agent_context/snowflake/udfs/add_glossary_terms.py +61 -0
  18. datahub_agent_context/snowflake/udfs/add_owners.py +59 -0
  19. datahub_agent_context/snowflake/udfs/add_structured_properties.py +57 -0
  20. datahub_agent_context/snowflake/udfs/add_tags.py +61 -0
  21. datahub_agent_context/snowflake/udfs/base.py +45 -0
  22. datahub_agent_context/snowflake/udfs/get_dataset_queries.py +68 -0
  23. datahub_agent_context/snowflake/udfs/get_entities.py +47 -0
  24. datahub_agent_context/snowflake/udfs/get_lineage.py +61 -0
  25. datahub_agent_context/snowflake/udfs/get_lineage_paths_between.py +69 -0
  26. datahub_agent_context/snowflake/udfs/get_me.py +51 -0
  27. datahub_agent_context/snowflake/udfs/grep_documents.py +70 -0
  28. datahub_agent_context/snowflake/udfs/list_schema_fields.py +80 -0
  29. datahub_agent_context/snowflake/udfs/remove_domains.py +45 -0
  30. datahub_agent_context/snowflake/udfs/remove_glossary_terms.py +57 -0
  31. datahub_agent_context/snowflake/udfs/remove_owners.py +56 -0
  32. datahub_agent_context/snowflake/udfs/remove_structured_properties.py +56 -0
  33. datahub_agent_context/snowflake/udfs/remove_tags.py +57 -0
  34. datahub_agent_context/snowflake/udfs/search_datahub.py +71 -0
  35. datahub_agent_context/snowflake/udfs/search_documents.py +58 -0
  36. datahub_agent_context/snowflake/udfs/set_domains.py +55 -0
  37. datahub_agent_context/snowflake/udfs/update_description.py +60 -0
  38. {datahub_agent_context-1.3.1.10rc1.dist-info → datahub_agent_context-1.4.0rc2.dist-info}/METADATA +21 -14
  39. datahub_agent_context-1.4.0rc2.dist-info/RECORD +66 -0
  40. datahub_agent_context-1.3.1.10rc1.dist-info/RECORD +0 -34
  41. {datahub_agent_context-1.3.1.10rc1.dist-info → datahub_agent_context-1.4.0rc2.dist-info}/WHEEL +0 -0
  42. {datahub_agent_context-1.3.1.10rc1.dist-info → datahub_agent_context-1.4.0rc2.dist-info}/top_level.txt +0 -0
@@ -17,9 +17,17 @@
17
17
  from datahub_agent_context._version import __version__
18
18
  from datahub_agent_context.context import (
19
19
  DataHubContext,
20
+ get_datahub_client,
20
21
  get_graph,
21
- reset_graph,
22
- set_graph,
22
+ reset_client,
23
+ set_client,
23
24
  )
24
25
 
25
- __all__ = ["__version__", "DataHubContext", "get_graph", "set_graph", "reset_graph"]
26
+ __all__ = [
27
+ "__version__",
28
+ "DataHubContext",
29
+ "get_datahub_client",
30
+ "get_graph",
31
+ "set_client",
32
+ "reset_client",
33
+ ]
@@ -13,4 +13,4 @@
13
13
  # limitations under the License.
14
14
 
15
15
  __package_name__ = "datahub-agent-context"
16
- __version__ = "1.3.1.10rc1"
16
+ __version__ = "1.4.0rc2"
@@ -0,0 +1,152 @@
1
+ import logging
2
+
3
+ import click
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+
8
+ @click.group()
9
+ def agent() -> None:
10
+ """Helper commands for Creating and managing Agent on DataHub."""
11
+ pass
12
+
13
+
14
+ @agent.group()
15
+ def create() -> None:
16
+ """Create an agent on DataHub."""
17
+ pass
18
+
19
+
20
+ @create.command(name="snowflake")
21
+ @click.option(
22
+ "--sf-account",
23
+ default=None,
24
+ help="Snowflake account identifier (auto-detected if not provided)",
25
+ )
26
+ @click.option(
27
+ "--sf-user",
28
+ default=None,
29
+ help="Snowflake user name (auto-detected if not provided)",
30
+ )
31
+ @click.option(
32
+ "--sf-role",
33
+ default=None,
34
+ help="Snowflake role (auto-detected if not provided)",
35
+ )
36
+ @click.option(
37
+ "--sf-warehouse",
38
+ default=None,
39
+ help="Snowflake warehouse name (auto-detected if not provided)",
40
+ )
41
+ @click.option(
42
+ "--sf-database",
43
+ default=None,
44
+ help="Snowflake database name (auto-detected if not provided)",
45
+ )
46
+ @click.option(
47
+ "--sf-schema",
48
+ default=None,
49
+ help="Snowflake schema name (auto-detected if not provided)",
50
+ )
51
+ @click.option("--datahub-url", required=True, help="DataHub instance URL")
52
+ @click.option("--datahub-token", required=True, help="DataHub Personal Access Token")
53
+ @click.option(
54
+ "--agent-name", default="DATAHUB_SQL_AGENT", help="Agent name in Snowflake"
55
+ )
56
+ @click.option(
57
+ "--agent-display-name",
58
+ default="DataHub SQL Assistant",
59
+ help="Agent display name in Snowflake UI",
60
+ )
61
+ @click.option(
62
+ "--agent-color",
63
+ default="blue",
64
+ help="Agent color in Snowflake UI",
65
+ type=click.Choice(["blue", "red", "green", "yellow", "purple", "orange"]),
66
+ )
67
+ @click.option(
68
+ "--output-dir",
69
+ default="./snowflake_setup",
70
+ help="Output directory for generated SQL files",
71
+ )
72
+ @click.option(
73
+ "--execute",
74
+ is_flag=True,
75
+ default=False,
76
+ help="Connect to Snowflake and execute the SQL scripts directly",
77
+ )
78
+ @click.option(
79
+ "--sf-password",
80
+ help="Snowflake password (required if --execute is used with password authentication)",
81
+ )
82
+ @click.option(
83
+ "--sf-authenticator",
84
+ default="snowflake",
85
+ type=click.Choice(["snowflake", "externalbrowser", "oauth"], case_sensitive=False),
86
+ help="Authentication method: 'snowflake' (password), 'externalbrowser' (SSO), or 'oauth' (token-based). Default: snowflake",
87
+ )
88
+ @click.option(
89
+ "--enable-mutations/--no-enable-mutations",
90
+ default=True,
91
+ help="Include mutation/write tools (tags, descriptions, owners, etc.). Default: enabled",
92
+ )
93
+ def create_snowflake(
94
+ sf_account: str | None,
95
+ sf_user: str | None,
96
+ sf_role: str | None,
97
+ sf_warehouse: str | None,
98
+ sf_database: str | None,
99
+ sf_schema: str | None,
100
+ datahub_url: str,
101
+ datahub_token: str,
102
+ agent_name: str,
103
+ agent_display_name: str,
104
+ agent_color: str,
105
+ output_dir: str,
106
+ execute: bool,
107
+ sf_password: str | None,
108
+ sf_authenticator: str,
109
+ enable_mutations: bool,
110
+ ) -> None:
111
+ """Create a Snowflake agent on DataHub.
112
+
113
+ Snowflake connection parameters (account, user, role, warehouse, database, schema)
114
+ will be auto-detected from your current session if not provided explicitly.
115
+
116
+ Authentication methods:
117
+ - snowflake (default): Standard password authentication
118
+ - externalbrowser: SSO authentication via browser (no password required)
119
+ - oauth: OAuth token-based authentication
120
+
121
+ Examples:
122
+ # Generate SQL files only (default)
123
+ $ datahub agent create snowflake --datahub-url=... --datahub-token=...
124
+
125
+ # Execute with password authentication
126
+ $ datahub agent create snowflake --execute --sf-password=secret ...
127
+
128
+ # Execute with SSO authentication (browser-based)
129
+ $ datahub agent create snowflake --execute --sf-authenticator=externalbrowser ...
130
+ """
131
+ from datahub_agent_context.snowflake.snowflake import create_snowflake_agent
132
+
133
+ ctx = click.get_current_context()
134
+ ctx.invoke(
135
+ create_snowflake_agent,
136
+ sf_account=sf_account,
137
+ sf_user=sf_user,
138
+ sf_role=sf_role,
139
+ sf_warehouse=sf_warehouse,
140
+ sf_database=sf_database,
141
+ sf_schema=sf_schema,
142
+ datahub_url=datahub_url,
143
+ datahub_token=datahub_token,
144
+ agent_name=agent_name,
145
+ agent_display_name=agent_display_name,
146
+ agent_color=agent_color,
147
+ output_dir=output_dir,
148
+ execute=execute,
149
+ sf_password=sf_password,
150
+ sf_authenticator=sf_authenticator,
151
+ enable_mutations=enable_mutations,
152
+ )
@@ -1,6 +1,6 @@
1
1
  """Context management for DataHub tools.
2
2
 
3
- This module provides a context manager pattern for managing DataHubGraph instances
3
+ This module provides a context manager pattern for managing DataHubClient instances
4
4
  across tool calls without explicit parameter passing.
5
5
  """
6
6
 
@@ -9,56 +9,69 @@ from typing import TYPE_CHECKING, Optional
9
9
 
10
10
  if TYPE_CHECKING:
11
11
  from datahub.ingestion.graph.client import DataHubGraph
12
+ from datahub.sdk.main_client import DataHubClient
12
13
 
13
- # Context variable to store the current DataHubGraph instance
14
- _graph_context: contextvars.ContextVar[Optional["DataHubGraph"]] = (
15
- contextvars.ContextVar("datahub_graph", default=None)
14
+ # Context variable to store the current DataHubClient instance
15
+ _client_context: contextvars.ContextVar[Optional["DataHubClient"]] = (
16
+ contextvars.ContextVar("datahub_client", default=None)
16
17
  )
17
18
 
18
19
 
19
- def get_graph() -> "DataHubGraph":
20
- """Get the current DataHubGraph from context.
20
+ def get_datahub_client() -> "DataHubClient":
21
+ """Get the current DataHubClient from context.
21
22
 
22
23
  Returns:
23
- DataHubGraph instance from context
24
+ DataHubClient instance from context
24
25
 
25
26
  Raises:
26
- RuntimeError: If no graph is set in context
27
+ RuntimeError: If no client is set in context
27
28
  """
28
- graph = _graph_context.get()
29
- if graph is None:
29
+ client = _client_context.get()
30
+ if client is None:
30
31
  raise RuntimeError(
31
- "No DataHubGraph in context. "
32
- "Make sure to use DataHubContext context manager or set_graph() before calling tools."
32
+ "No DataHubClient in context. "
33
+ "Make sure to use DataHubContext context manager or set_client() before calling tools."
33
34
  )
34
- return graph
35
+ return client
36
+
37
+
38
+ def get_graph() -> "DataHubGraph":
39
+ """Get the current DataHubGraph from context (convenience method).
40
+
41
+ Returns:
42
+ DataHubGraph instance from the client in context
43
+
44
+ Raises:
45
+ RuntimeError: If no client is set in context
46
+ """
47
+ return get_datahub_client()._graph
35
48
 
36
49
 
37
- def set_graph(graph: "DataHubGraph") -> contextvars.Token:
38
- """Set the DataHubGraph in context.
50
+ def set_client(client: "DataHubClient") -> contextvars.Token:
51
+ """Set the DataHubClient in context.
39
52
 
40
53
  Args:
41
- graph: DataHubGraph instance to set
54
+ client: DataHubClient instance to set
42
55
 
43
56
  Returns:
44
57
  Token that can be used to reset the context
45
58
  """
46
- return _graph_context.set(graph)
59
+ return _client_context.set(client)
47
60
 
48
61
 
49
- def reset_graph(token: contextvars.Token) -> None:
50
- """Reset the DataHubGraph context to its previous value.
62
+ def reset_client(token: contextvars.Token) -> None:
63
+ """Reset the DataHubClient context to its previous value.
51
64
 
52
65
  Args:
53
- token: Token returned by set_graph()
66
+ token: Token returned by set_client()
54
67
  """
55
- _graph_context.reset(token)
68
+ _client_context.reset(token)
56
69
 
57
70
 
58
71
  class DataHubContext:
59
72
  """Context manager for DataHub tool execution.
60
73
 
61
- This context manager sets the DataHubGraph in context for the duration
74
+ This context manager sets the DataHubClient in context for the duration
62
75
  of the with block, allowing tools to access it without explicit parameter passing.
63
76
 
64
77
  Example:
@@ -68,30 +81,30 @@ class DataHubContext:
68
81
 
69
82
  client = DataHubClient(...)
70
83
 
71
- with DataHubContext(client.graph):
72
- results = search(query="users") # No graph parameter needed!
84
+ with DataHubContext(client):
85
+ results = search(query="users") # No client parameter needed!
73
86
  """
74
87
 
75
- def __init__(self, graph: "DataHubGraph"):
88
+ def __init__(self, client: "DataHubClient"):
76
89
  """Initialize the context manager.
77
90
 
78
91
  Args:
79
- graph: DataHubGraph instance to use in this context
92
+ client: DataHubClient instance to use in this context
80
93
  """
81
- self.graph = graph
94
+ self.client = client
82
95
  self._token: Optional[contextvars.Token] = None
83
96
 
84
- def __enter__(self) -> "DataHubGraph":
85
- """Enter the context and set the graph.
97
+ def __enter__(self) -> "DataHubClient":
98
+ """Enter the context and set the client.
86
99
 
87
100
  Returns:
88
- The DataHubGraph instance
101
+ The DataHubClient instance
89
102
  """
90
- self._token = set_graph(self.graph)
91
- return self.graph
103
+ self._token = set_client(self.client)
104
+ return self.client
92
105
 
93
106
  def __exit__(self, exc_type, exc_val, exc_tb) -> None:
94
- """Exit the context and reset the graph."""
107
+ """Exit the context and reset the client."""
95
108
  if self._token is not None:
96
- reset_graph(self._token)
109
+ reset_client(self._token)
97
110
  self._token = None
@@ -3,7 +3,7 @@
3
3
  import functools
4
4
  from typing import TYPE_CHECKING, Callable
5
5
 
6
- from datahub_agent_context.context import set_graph
6
+ from datahub_agent_context.context import set_client
7
7
  from datahub_agent_context.mcp_tools import get_me
8
8
  from datahub_agent_context.mcp_tools.documents import grep_documents, search_documents
9
9
  from datahub_agent_context.mcp_tools.domains import remove_domains, set_domains
@@ -32,6 +32,7 @@ from datahub_agent_context.mcp_tools.lineage import (
32
32
  )
33
33
  from datahub_agent_context.mcp_tools.owners import add_owners, remove_owners
34
34
  from datahub_agent_context.mcp_tools.queries import get_dataset_queries
35
+ from datahub_agent_context.mcp_tools.save_document import save_document
35
36
  from datahub_agent_context.mcp_tools.search import search
36
37
  from datahub_agent_context.mcp_tools.tags import add_tags, remove_tags
37
38
  from datahub_agent_context.mcp_tools.terms import (
@@ -57,14 +58,14 @@ def create_context_wrapper(func: Callable, client: "DataHubClient") -> Callable:
57
58
  @functools.wraps(func)
58
59
  def wrapper(*args, **kwargs):
59
60
  # Set graph in context for this function call
60
- token = set_graph(client._graph)
61
+ token = set_client(client)
61
62
  try:
62
63
  return func(*args, **kwargs)
63
64
  finally:
64
65
  # Always reset context, even if function raises
65
- from datahub_agent_context.context import reset_graph
66
+ from datahub_agent_context.context import reset_client
66
67
 
67
- reset_graph(token)
68
+ reset_client(token)
68
69
 
69
70
  return wrapper
70
71
 
@@ -123,5 +124,6 @@ def build_langchain_tools(
123
124
  tools.append(tool(create_context_wrapper(remove_tags, client)))
124
125
  tools.append(tool(create_context_wrapper(add_glossary_terms, client)))
125
126
  tools.append(tool(create_context_wrapper(remove_glossary_terms, client)))
127
+ tools.append(tool(create_context_wrapper(save_document, client)))
126
128
 
127
129
  return tools
@@ -152,9 +152,12 @@ def _is_datahub_cloud(graph: DataHubGraph) -> bool:
152
152
  )
153
153
  return False
154
154
 
155
- is_cloud = hasattr(graph, "frontend_base_url") and graph.frontend_base_url
156
- logger.debug(f"Cloud detection: {is_cloud}")
157
- return bool(is_cloud)
155
+ try:
156
+ is_cloud = hasattr(graph, "frontend_base_url") and graph.frontend_base_url
157
+ logger.debug(f"Cloud detection: {is_cloud}")
158
+ return bool(is_cloud)
159
+ except ValueError:
160
+ return False
158
161
 
159
162
 
160
163
  def _is_field_validation_error(error_msg: str) -> bool: