Commit
·
8942d03
1
Parent(s):
7141c1f
add pagination to list_nodes_by_type
Browse files- gradio_mcp_space.py +35 -9
gradio_mcp_space.py
CHANGED
|
@@ -342,7 +342,7 @@ Node Types:
|
|
| 342 |
|
| 343 |
|
| 344 |
@observe(as_type="tool")
|
| 345 |
-
def list_nodes_by_type(node_type: str, limit: int = 20) -> str:
|
| 346 |
"""
|
| 347 |
List nodes of a specific type in the knowledge graph.
|
| 348 |
|
|
@@ -357,13 +357,24 @@ def list_nodes_by_type(node_type: str, limit: int = 20) -> str:
|
|
| 357 |
return "Error: Knowledge graph not initialized"
|
| 358 |
|
| 359 |
try:
|
| 360 |
-
# Convert limit to int if
|
| 361 |
if isinstance(limit, str):
|
| 362 |
try:
|
| 363 |
limit = int(limit)
|
| 364 |
except ValueError:
|
| 365 |
return f"Error: 'limit' must be an integer, got '{limit}'"
|
| 366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
g = knowledge_graph.graph
|
| 368 |
matching_nodes = [
|
| 369 |
{
|
|
@@ -372,18 +383,32 @@ def list_nodes_by_type(node_type: str, limit: int = 20) -> str:
|
|
| 372 |
}
|
| 373 |
for node_id, data in g.nodes(data=True)
|
| 374 |
if getattr(data['data'], 'node_type', None) == node_type
|
| 375 |
-
]
|
| 376 |
|
| 377 |
-
|
|
|
|
| 378 |
return f"No nodes found of type '{node_type}'."
|
| 379 |
|
| 380 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 381 |
result += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
| 382 |
|
| 383 |
-
for i, node in enumerate(
|
| 384 |
result += f"{i}. {node['name']}\n"
|
| 385 |
result += f" ID: {node['id']}\n\n"
|
| 386 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 387 |
return result
|
| 388 |
except Exception as e:
|
| 389 |
return f"Error: {str(e)}"
|
|
@@ -440,7 +465,7 @@ def get_neighbors(node_id: str) -> str:
|
|
| 440 |
@observe(as_type="tool")
|
| 441 |
def go_to_definition(entity_name: str) -> str:
|
| 442 |
"""
|
| 443 |
-
Retrieve where
|
| 444 |
|
| 445 |
Locates and retrieves the declaration point for functions, classes, variables, etc.
|
| 446 |
|
|
@@ -1869,10 +1894,11 @@ def create_gradio_app():
|
|
| 1869 |
label="Node Type"
|
| 1870 |
)
|
| 1871 |
type_limit = gr.Slider(1, 100, value=20, step=1, label="Max Results")
|
|
|
|
| 1872 |
type_btn = gr.Button("List Nodes", variant="primary")
|
| 1873 |
with gr.Column():
|
| 1874 |
type_output = gr.Textbox(label="Results", lines=20, max_lines=30)
|
| 1875 |
-
type_btn.click(fn=list_nodes_by_type, inputs=[node_type_input, type_limit], outputs=type_output)
|
| 1876 |
gr.Markdown(_tool_doc_md(list_nodes_by_type))
|
| 1877 |
|
| 1878 |
gr.Markdown("---")
|
|
|
|
| 342 |
|
| 343 |
|
| 344 |
@observe(as_type="tool")
|
| 345 |
+
def list_nodes_by_type(node_type: str, limit: int = 20, page: int = 1) -> str:
|
| 346 |
"""
|
| 347 |
List nodes of a specific type in the knowledge graph.
|
| 348 |
|
|
|
|
| 357 |
return "Error: Knowledge graph not initialized"
|
| 358 |
|
| 359 |
try:
|
| 360 |
+
# Convert limit/page to int if they're strings (MCP/Gradio may pass strings)
|
| 361 |
if isinstance(limit, str):
|
| 362 |
try:
|
| 363 |
limit = int(limit)
|
| 364 |
except ValueError:
|
| 365 |
return f"Error: 'limit' must be an integer, got '{limit}'"
|
| 366 |
+
|
| 367 |
+
if isinstance(page, str):
|
| 368 |
+
try:
|
| 369 |
+
page = int(page)
|
| 370 |
+
except ValueError:
|
| 371 |
+
return f"Error: 'page' must be an integer, got '{page}'"
|
| 372 |
+
|
| 373 |
+
if limit <= 0:
|
| 374 |
+
return "Error: limit must be a positive integer"
|
| 375 |
+
if page < 1:
|
| 376 |
+
return "Error: 'page' must be a positive integer (1 or greater)"
|
| 377 |
+
|
| 378 |
g = knowledge_graph.graph
|
| 379 |
matching_nodes = [
|
| 380 |
{
|
|
|
|
| 383 |
}
|
| 384 |
for node_id, data in g.nodes(data=True)
|
| 385 |
if getattr(data['data'], 'node_type', None) == node_type
|
| 386 |
+
]
|
| 387 |
|
| 388 |
+
total = len(matching_nodes)
|
| 389 |
+
if total == 0:
|
| 390 |
return f"No nodes found of type '{node_type}'."
|
| 391 |
|
| 392 |
+
# Pagination
|
| 393 |
+
total_pages = (total + limit - 1) // limit
|
| 394 |
+
if page > total_pages:
|
| 395 |
+
return f"Error: Page {page} does not exist. Total pages: {total_pages} (with {total} nodes at {limit} per page)"
|
| 396 |
+
|
| 397 |
+
start_idx = (page - 1) * limit
|
| 398 |
+
end_idx = start_idx + limit
|
| 399 |
+
page_slice = matching_nodes[start_idx:end_idx]
|
| 400 |
+
|
| 401 |
+
result = f"Nodes of type '{node_type}' (Page {page}/{total_pages}, {total} total):\n"
|
| 402 |
result += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
| 403 |
|
| 404 |
+
for i, node in enumerate(page_slice, start=start_idx + 1):
|
| 405 |
result += f"{i}. {node['name']}\n"
|
| 406 |
result += f" ID: {node['id']}\n\n"
|
| 407 |
|
| 408 |
+
# Pagination hint
|
| 409 |
+
if page < total_pages:
|
| 410 |
+
result += f"Use page={page + 1} to see the next page\n"
|
| 411 |
+
|
| 412 |
return result
|
| 413 |
except Exception as e:
|
| 414 |
return f"Error: {str(e)}"
|
|
|
|
| 465 |
@observe(as_type="tool")
|
| 466 |
def go_to_definition(entity_name: str) -> str:
|
| 467 |
"""
|
| 468 |
+
Retrieve chunk node(s) where entity is declared or defined in the codebase.
|
| 469 |
|
| 470 |
Locates and retrieves the declaration point for functions, classes, variables, etc.
|
| 471 |
|
|
|
|
| 1894 |
label="Node Type"
|
| 1895 |
)
|
| 1896 |
type_limit = gr.Slider(1, 100, value=20, step=1, label="Max Results")
|
| 1897 |
+
type_page = gr.Slider(1, 100, value=1, step=1, label="Page")
|
| 1898 |
type_btn = gr.Button("List Nodes", variant="primary")
|
| 1899 |
with gr.Column():
|
| 1900 |
type_output = gr.Textbox(label="Results", lines=20, max_lines=30)
|
| 1901 |
+
type_btn.click(fn=list_nodes_by_type, inputs=[node_type_input, type_limit, type_page], outputs=type_output)
|
| 1902 |
gr.Markdown(_tool_doc_md(list_nodes_by_type))
|
| 1903 |
|
| 1904 |
gr.Markdown("---")
|