Skip to content

Commit 3ee076b

Browse files
authored
Merge pull request #14 from GoogleCloudPlatform/refactor/rename-fragment-to-facet
Refactor: Rename ContextSet "fragment" to "facet"
2 parents 9df803d + 888a095 commit 3ee076b

15 files changed

+209
-100
lines changed

gemini-extension.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mcp-db-context-enrichment",
3-
"version": "0.1.6",
3+
"version": "0.2.0",
44
"contextFileName": "./mcp/GEMINI.md",
55
"mcpServers": {
66
"mcp_db_context_enrichment": {
@@ -9,7 +9,7 @@
99
"tool",
1010
"run",
1111
"--from",
12-
"${extensionPath}${/}mcp${/}dist${/}db_context_enrichment-0.1.6-py3-none-any.whl",
12+
"${extensionPath}${/}mcp${/}dist${/}db_context_enrichment-0.2.0-py3-none-any.whl",
1313
"db-context-enrichment"
1414
]
1515
}

mcp/GEMINI.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Project Overview
22

3-
This project is a FastMCP server for "DB Context Enrichment." It provides a guided workflow to generate structured, natural language-to-SQL templates and SQL fragments from a user's database schema.
3+
This project is a FastMCP server for "DB Context Enrichment." It provides a guided workflow to generate structured, natural language-to-SQL templates and SQL facets from a user's database schema.
44

55
**Crucially, this server depends on a running MCP Toolbox server to provide the underlying tools for database connection and schema fetching.**
66

@@ -44,7 +44,7 @@ When using the `attach_context_set` tool, the Gemini CLI should **not** read the
4444

4545
## ContextSet Structure
4646

47-
The `ContextSet` object is a JSON structure that can contain both `templates` and `fragments`. It is the standardized output format for `generate_templates` and `generate_fragments` tools, and the expected input for `save_context_set` and `attach_context_set`.
47+
The `ContextSet` object is a JSON structure that can contain both `templates` and `facets`. It is the standardized output format for `generate_templates` and `generate_facets` tools, and the expected input for `save_context_set` and `attach_context_set`.
4848

4949
**Example ContextSet JSON:**
5050

@@ -62,13 +62,13 @@ The `ContextSet` object is a JSON structure that can contain both `templates` an
6262
}
6363
}
6464
],
65-
"fragments": [
65+
"facets": [
6666
{
67-
"fragment": "description LIKE '%luxury%' OR description LIKE '%premium%'",
67+
"sql_snippet": "description LIKE '%luxury%' OR description LIKE '%premium%'",
6868
"intent": "luxury product",
6969
"manifest": "luxury product",
7070
"parameterized": {
71-
"parameterized_fragment": "description LIKE '%luxury%' OR description LIKE '%premium%'",
71+
"parameterized_sql_snippet": "description LIKE '%luxury%' OR description LIKE '%premium%'",
7272
"parameterized_intent": "luxury product"
7373
}
7474
}
-15.1 KB
Binary file not shown.
-13.1 KB
Binary file not shown.
15.2 KB
Binary file not shown.
13 KB
Binary file not shown.
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
from model import context
44

55

6-
async def generate_fragments_from_pairs(
6+
async def generate_facets_from_pairs(
77
approved_pairs_json: str, db_dialect_str: str = "postgresql"
88
) -> str:
99
"""
10-
Generates the final, detailed fragments based on user-approved question/SQL fragment pairs.
10+
Generates the final, detailed facets based on user-approved question/SQL facet pairs.
1111
"""
1212
try:
1313
# Convert the string to the Enum member
@@ -23,11 +23,11 @@ async def generate_fragments_from_pairs(
2323
except json.JSONDecodeError:
2424
return '{"error": "Invalid JSON format for approved pairs. Expected a JSON array."}'
2525

26-
final_fragments = []
26+
final_facets = []
2727

2828
for pair in pair_list:
2929
question = pair["question"]
30-
fragment_text = pair["fragment"]
30+
facet_text = pair["facet"]
3131
intent = question # The intent starts as the original question
3232

3333
# 1. Extract value phrases from the question
@@ -44,20 +44,20 @@ async def generate_fragments_from_pairs(
4444

4545
# 3. Parameterize the SQL and Intent
4646
parameterized_result = parameterizer.parameterize_sql_and_intent(
47-
phrases, fragment_text, intent, db_dialect=db_dialect
47+
phrases, facet_text, intent, db_dialect=db_dialect
4848
)
4949

50-
# 4. Assemble the final fragment object
51-
fragment = context.Fragment(
52-
fragment=fragment_text,
50+
# 4. Assemble the final facet object
51+
facet = context.Facet(
52+
sql_snippet=facet_text,
5353
intent=intent,
5454
manifest=manifest,
55-
parameterized=context.ParameterizedFragment(
56-
parameterized_fragment=parameterized_result["sql"],
55+
parameterized=context.ParameterizedFacet(
56+
parameterized_sql_snippet=parameterized_result["sql"],
5757
parameterized_intent=parameterized_result["intent"],
5858
),
5959
)
60-
final_fragments.append(fragment)
60+
final_facets.append(facet)
6161

62-
context_set = context.ContextSet(templates=None, fragments=final_fragments)
62+
context_set = context.ContextSet(templates=None, facets=final_facets)
6363
return context_set.model_dump_json(indent=2, exclude_none=True)

mcp/main.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Optional, List
33
import textwrap
44
from template import question_generator, template_generator
5-
from fragment import fragment_generator
5+
from facet import facet_generator
66
from model import context
77
import datetime
88
import os
@@ -64,16 +64,16 @@ async def generate_templates(
6464

6565

6666
@mcp.tool
67-
async def generate_fragments(
67+
async def generate_facets(
6868
approved_pairs_json: str, db_engine: Optional[str] = "postgresql"
6969
) -> str:
7070
"""
71-
Generates final fragments from a list of user-approved question/SQL fragment pairs.
71+
Generates final facets from a list of user-approved question/SQL facet pairs.
7272
7373
Args:
7474
approved_pairs_json: A JSON string representing a list of dictionaries,
75-
where each dictionary has a "question" and a "fragment" key.
76-
Example: '[{"question": "...", "fragment": "..."}]'
75+
where each dictionary has a "question" and a "facet" key.
76+
Example: '[{"question": "...", "facet": "..."}]'
7777
db_engine: The SQL dialect to use for parameterization. Accepted
7878
values are 'postgresql', 'mysql', or 'googlesql'.
7979
@@ -82,7 +82,7 @@ async def generate_fragments(
8282
"""
8383
# Ensure we pass a string, defaulting to 'postgresql' if None is provided.
8484
dialect = db_engine if db_engine is not None else "postgresql"
85-
return await fragment_generator.generate_fragments_from_pairs(
85+
return await facet_generator.generate_facets_from_pairs(
8686
approved_pairs_json, dialect
8787
)
8888

@@ -129,18 +129,18 @@ def attach_context_set(
129129
Attaches a ContextSet to an existing JSON file.
130130
131131
This tool reads an existing JSON file containing a ContextSet,
132-
appends new templates/fragments to it, and writes the updated ContextSet
132+
appends new templates/facets to it, and writes the updated ContextSet
133133
back to the file. Exceptions are propagated to the caller.
134134
135135
Args:
136-
context_set_json: The JSON string output from the `generate_templates` or `generate_fragments` tool.
136+
context_set_json: The JSON string output from the `generate_templates` or `generate_facets` tool.
137137
file_path: The **absolute path** to the existing template file.
138138
139139
Returns:
140140
A confirmation message with the path to the updated file.
141141
"""
142142

143-
existing_content_dict = {"templates": [], "fragments": []}
143+
existing_content_dict = {"templates": [], "facets": []}
144144
if os.path.getsize(file_path) > 0:
145145
with open(file_path, "r") as f:
146146
existing_content_dict = json.load(f)
@@ -154,10 +154,10 @@ def attach_context_set(
154154
if new_context.templates:
155155
existing_context.templates.extend(new_context.templates)
156156

157-
if existing_context.fragments is None:
158-
existing_context.fragments = []
159-
if new_context.fragments:
160-
existing_context.fragments.extend(new_context.fragments)
157+
if existing_context.facets is None:
158+
existing_context.facets = []
159+
if new_context.facets:
160+
existing_context.facets.extend(new_context.facets)
161161

162162
with open(file_path, "w") as f:
163163
json.dump(existing_context.model_dump(), f, indent=2)
@@ -353,37 +353,37 @@ def generate_targeted_templates() -> str:
353353

354354

355355
@mcp.prompt
356-
def generate_targeted_fragments() -> str:
357-
"""Initiates a guided workflow to generate specific Phrase/SQL fragment pair templates."""
356+
def generate_targeted_facets() -> str:
357+
"""Initiates a guided workflow to generate specific Phrase/SQL facet pair templates."""
358358
return textwrap.dedent(
359359
"""
360-
**Workflow for Generating Targeted Phrase/SQL Fragment Pair Templates**
360+
**Workflow for Generating Targeted Phrase/SQL Facet Pair Templates**
361361
362362
1. **User Input Loop:**
363-
- Ask the user to provide a natural language phrase and its corresponding SQL fragment.
363+
- Ask the user to provide a natural language phrase and its corresponding SQL facet.
364364
- After capturing the pair, ask the user if they would like to add another one.
365365
- Continue this loop until the user indicates they have no more pairs to add.
366366
367367
2. **Review and Confirmation:**
368-
- Present the complete list of user-provided Phrase/SQL fragment pairs for confirmation.
368+
- Present the complete list of user-provided Phrase/SQL facet pairs for confirmation.
369369
- **Use the following format for each pair:**
370370
**Pair [Number]**
371371
**Phrase:** [The natural language phrase]
372-
**Fragment:**
372+
**Facet:**
373373
```sql
374-
[The SQL fragment, properly formatted]
374+
[The SQL facet, properly formatted]
375375
```
376376
- Ask if any modifications are needed. If so, work with the user to refine the pairs.
377377
378-
3. **Final Fragment Generation:**
379-
- Once approved, call the `generate_fragments` tool with the approved pairs.
380-
- **Note:** If the number of approved pairs is very large (e.g., over 50), break the list into smaller chunks and call the `generate_fragments` tool for each chunk.
378+
3. **Final Facet Generation:**
379+
- Once approved, call the `generate_facets` tool with the approved pairs.
380+
- **Note:** If the number of approved pairs is very large (e.g., over 50), break the list into smaller chunks and call the `generate_facets` tool for each chunk.
381381
- The tool will return the final JSON content as a string.
382382
383-
4. **Save Fragments:**
383+
4. **Save Facets:**
384384
- Ask the user to choose one of the following options:
385385
1. Create a new context set file.
386-
2. Append fragments to an existing context set file.
386+
2. Append facets to an existing context set file.
387387
388388
- **If creating a new file:**
389389
- You will need to ask the user for the database instance and database name to create the filename.

mcp/model/context.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from pydantic import BaseModel, Field
1+
from pydantic import AliasChoices, BaseModel, Field
22
from typing import List, Optional
33

44

@@ -27,31 +27,45 @@ class Template(BaseModel):
2727
parameterized: ParameterizedTemplate
2828

2929

30-
class ParameterizedFragment(BaseModel):
31-
"""Defines the parameterized version of a SQL fragment and intent."""
30+
class ParameterizedFacet(BaseModel):
31+
"""Defines the parameterized version of a SQL facet and intent."""
3232

33-
parameterized_fragment: str = Field(
34-
..., description="The SQL fragment with placeholders (eg., )."
33+
parameterized_sql_snippet: str = Field(
34+
...,
35+
description="The SQL facet with placeholders (eg., ).",
36+
validation_alias=AliasChoices(
37+
"parameterized_sql_snippet", "parameterized_fragment"
38+
),
3539
)
3640
parameterized_intent: str = Field(
3741
..., description="The natural language intent with placeholders."
3842
)
3943

4044

41-
class Fragment(BaseModel):
42-
"""Represents a single, complete fragment."""
45+
class Facet(BaseModel):
46+
"""Represents a single, complete facet."""
4347

44-
fragment: str = Field(..., description="The corresponding, complete SQL fragment.")
48+
sql_snippet: str = Field(
49+
...,
50+
description="The corresponding, complete SQL facet.",
51+
validation_alias=AliasChoices("sql_snippet", "fragment"),
52+
)
4553
intent: str = Field(..., description="The user's specific intent.")
4654
manifest: str = Field(
47-
..., description="A general description of what the fragment does."
55+
..., description="A general description of what the facet does."
4856
)
49-
parameterized: ParameterizedFragment
57+
parameterized: ParameterizedFacet
5058

5159

5260
class ContextSet(BaseModel):
53-
"""A set of templates and fragments."""
61+
"""A set of templates and facets."""
5462

55-
templates: Optional[List[Template]] = Field(None, description="A list of complete templates.")
56-
fragments: Optional[List[Fragment]] = Field(None, description="A list of SQL fragments.")
63+
templates: Optional[List[Template]] = Field(
64+
None, description="A list of complete templates."
65+
)
66+
facets: Optional[List[Facet]] = Field(
67+
None,
68+
description="A list of SQL facets.",
69+
validation_alias=AliasChoices("facets", "fragments"),
70+
)
5771

0 commit comments

Comments
 (0)