Skip to content

Commit 0486bf5

Browse files
committed
address pr comments
1 parent 260eb51 commit 0486bf5

File tree

8 files changed

+31
-29
lines changed

8 files changed

+31
-29
lines changed

docs/topics/fenic-mcp.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ List, fetch, or drop tools:
132132

133133
```python
134134
all_tools = session.catalog.list_tools()
135-
age_tool = session.catalog.get_tool("users_by_age_range")
136-
search_tool = session.catalog.get_tool("users_by_name_regex")
135+
age_tool = session.catalog.describe_tool("users_by_age_range")
136+
search_tool = session.catalog.describe_tool("users_by_name_regex")
137137
session.catalog.drop_tool("users_by_age_range", ignore_if_not_exists=True)
138138
session.catalog.drop_tool("users_by_name_regex", ignore_if_not_exists=True)
139139
```

src/fenic/_backends/cloud/catalog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ def set_view_description(self, view_name: str, description: str) -> bool:
341341
"Set view description not implemented for cloud catalog"
342342
)
343343

344-
def get_tool(
344+
def describe_tool(
345345
self,
346346
tool_name: str,
347347
ignore_if_not_exists: bool = True,

src/fenic/_backends/local/catalog.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -510,13 +510,11 @@ def set_view_description(self, view_name: str, description: Optional[str]) -> bo
510510
) from e
511511

512512

513-
def get_tool(self, tool_name: str, ignore_if_not_exists: bool = True) -> Optional[ParameterizedToolDefinition]:
513+
def describe_tool(self, tool_name: str) -> Optional[ParameterizedToolDefinition]:
514514
"""Get a tool's metadata from the system table."""
515515
cursor = self.db_conn.cursor()
516-
existing_tool = self.system_tables.get_tool(cursor, tool_name)
517-
if existing_tool:
518-
if ignore_if_not_exists:
519-
return None
516+
existing_tool = self.system_tables.describe_tool(cursor, tool_name)
517+
if not existing_tool:
520518
raise ToolNotFoundError(tool_name)
521519
return existing_tool
522520

@@ -533,7 +531,7 @@ def create_tool(
533531
# Ensure the tool is valid by resolving it.
534532
tool_definition = bind_tool(tool_name, tool_description, tool_params, result_limit, tool_query)
535533
cursor = self.db_conn.cursor()
536-
if self.system_tables.get_tool(cursor, tool_name):
534+
if self._does_tool_exist(cursor, tool_name):
537535
if ignore_if_exists:
538536
return False
539537
raise ToolAlreadyExistsError(tool_name)
@@ -548,7 +546,7 @@ def list_tools(self) -> List[ParameterizedToolDefinition]:
548546
def drop_tool(self, tool_name: str, ignore_if_not_exists: bool = True) -> bool:
549547
"""Drop a tool from the current catalog."""
550548
cursor = self.db_conn.cursor()
551-
if not self.system_tables.get_tool(cursor, tool_name):
549+
if not self._does_tool_exist(cursor, tool_name):
552550
if ignore_if_not_exists:
553551
return False
554552
raise ToolNotFoundError(tool_name)
@@ -691,6 +689,14 @@ def get_metrics_for_session(self, session_id: str) -> Dict[str, float]:
691689
"""Get metrics for a specific session from the metrics system read-only table."""
692690
return self.system_tables.get_metrics_for_session(self.db_conn.cursor(), session_id)
693691

692+
def _does_tool_exist(self, cursor: duckdb.DuckDBPyConnection, tool_name: str) -> bool:
693+
try:
694+
return self.system_tables.describe_tool(cursor, tool_name) is not None
695+
except Exception as e:
696+
raise CatalogError(
697+
f"Failed to check if tool: {tool_name} exists"
698+
) from e
699+
694700
def _does_table_exist(self, cursor: duckdb.DuckDBPyConnection, table_identifier: TableIdentifier) -> bool:
695701
try:
696702
return cursor.execute(

src/fenic/_backends/local/system_table_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ def save_tool(self, cursor: duckdb.DuckDBPyConnection, tool: ParameterizedToolDe
486486
f"Failed to save tool metadata for {tool.name}"
487487
) from e
488488

489-
def get_tool(self, cursor: duckdb.DuckDBPyConnection, tool_name: str) -> Optional[ParameterizedToolDefinition]:
489+
def describe_tool(self, cursor: duckdb.DuckDBPyConnection, tool_name: str) -> Optional[ParameterizedToolDefinition]:
490490
"""Get a tool's metadata from the system table.
491491
Raises:
492492
CatalogError: If the tool metadata cannot be retrieved.

src/fenic/api/catalog.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -654,22 +654,19 @@ def drop_view(self, view_name: str, ignore_if_not_exists: bool = True) -> bool:
654654
return self.catalog.drop_view(view_name, ignore_if_not_exists)
655655

656656
@validate_call(config=ConfigDict(strict=True))
657-
def get_tool(self, tool_name: str, ignore_if_not_exists: bool = True) -> ParameterizedToolDefinition:
657+
def describe_tool(self, tool_name: str) -> ParameterizedToolDefinition:
658658
"""Returns the tool with the specified name from the current catalog.
659659
660660
Args:
661661
tool_name (str): The name of the tool to get.
662-
ignore_if_not_exists (bool): If True, return None when the tool doesn't exist.
663-
If False, raise an error when the tool doesn't exist.
664-
Defaults to True.
665662
666663
Raises:
667-
ToolNotFoundError: If the tool doesn't exist and ignore_if_not_exists is False
664+
ToolNotFoundError: If the tool doesn't exist.
668665
669666
Returns:
670667
Tool: The tool with the specified name.
671668
"""
672-
return self.catalog.get_tool(tool_name, ignore_if_not_exists)
669+
return self.catalog.describe_tool(tool_name)
673670

674671
@validate_call(config=ConfigDict(strict=True, arbitrary_types_allowed=True))
675672
def create_tool(
@@ -771,6 +768,6 @@ def list_tools(self) -> List[ParameterizedToolDefinition]:
771768
listViews = list_views
772769
doesViewExist = does_view_exist
773770
dropView = drop_view
774-
getTool = get_tool
771+
getTool = describe_tool
775772
createTool = create_tool
776773
dropTool = drop_tool

src/fenic/core/_interfaces/catalog.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def describe_view(self, view_name: str) -> DatasetMetadata:
145145
pass
146146

147147
@abstractmethod
148-
def get_tool(
148+
def describe_tool(
149149
self,
150150
tool_name: str,
151151
ignore_if_not_exists: bool = True

src/fenic/scripts/fenic_serve.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from fenic.api.mcp.tool_generation import ToolGenerationConfig
4343
from fenic.api.session.config import SessionConfig
4444
from fenic.api.session.session import Session
45-
from fenic.core.error import ConfigurationError
45+
from fenic.core.error import ConfigurationError, ToolNotFoundError
4646

4747

4848
def _parse_args() -> argparse.Namespace:
@@ -101,7 +101,10 @@ def main() -> None:
101101
tools = []
102102
if args.tools:
103103
for tool_name in args.tools:
104-
tools.append(session.catalog.get_tool(tool_name))
104+
try:
105+
tools.append(session.catalog.describe_tool(tool_name))
106+
except ToolNotFoundError as e:
107+
raise ConfigurationError(f"Tool {tool_name} not found in the catalog.") from e
105108
else:
106109
tools = session.catalog.list_tools()
107110

tools/mcp_demo_setup.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ class CandidateProfile(BaseModel):
122122
job_category_match = fc.coalesce(fc.tool_param("job_category_query", StringType).is_in(fc.col("job_category")), fc.lit(True))
123123
merged_filter = education_match & seniority_match & skills_match & experience_match & job_category_match
124124
search_candidates = candidates_df.filter(merged_filter).select("candidate_id", "first_name", "last_name", "education", "seniority", "skills", "experience", "job_category")
125-
if local_session.catalog.get_tool("search_candidates"):
126-
local_session.catalog.drop_tool("search_candidates")
125+
local_session.catalog.drop_tool("search_candidates")
127126
local_session.catalog.create_tool(
128127
"search_candidates",
129128
"Search candidates by education, seniority, skills, and experience using regex patterns.",
@@ -140,8 +139,7 @@ class CandidateProfile(BaseModel):
140139

141140
# Tool 2: candidate_resumes_by_candidate_ids -- given a list of candidate ids, return the raw resumes for each candidate
142141
candidate_resumes = candidates_df.filter(fc.col("candidate_id").is_in(fc.tool_param("candidate_ids", fc.ArrayType(element_type=IntegerType)))).select("candidate_id", "candidate_resume")
143-
if local_session.catalog.get_tool("candidate_resumes_by_candidate_ids"):
144-
local_session.catalog.drop_tool("candidate_resumes_by_candidate_ids")
142+
local_session.catalog.drop_tool("candidate_resumes_by_candidate_ids")
145143
local_session.catalog.create_tool(
146144
"candidate_resumes_by_candidate_ids",
147145
"Return the raw resumes for a list of candidate ids.",
@@ -208,8 +206,7 @@ class CandidateProfile(BaseModel):
208206
)
209207
job_category_match = fc.coalesce(fc.tool_param("job_category_query", StringType).is_in(fc.col("job_category")), fc.lit(True))
210208
candidates_for_job = candidates_df.filter(job_category_match).filter(fit_pred).select("candidate_id", "first_name", "last_name", "education", "seniority", "skills", "experience", "job_category")
211-
if local_session.catalog.get_tool("candidates_for_job_description"):
212-
local_session.catalog.drop_tool("candidates_for_job_description")
209+
local_session.catalog.drop_tool("candidates_for_job_description")
213210
local_session.catalog.create_tool(
214211
"candidates_for_job_description",
215212
"Find candidates who are a good fit for a free-form job description using structured profiles.",
@@ -279,8 +276,7 @@ class CandidateProfile(BaseModel):
279276
).alias("email"),
280277
)
281278
# Filter to a single candidate_id at runtime
282-
if local_session.catalog.get_tool("create_outreach_for_candidate"):
283-
local_session.catalog.drop_tool("create_outreach_for_candidate")
279+
local_session.catalog.drop_tool("create_outreach_for_candidate")
284280
local_session.catalog.create_tool(
285281
"create_outreach_for_candidate",
286282
"Create a personalized recruiting email for a candidate using resume and cover letter context.",

0 commit comments

Comments
 (0)