unify sayıştay tools

This commit is contained in:
saidsurucu
2025-07-17 20:44:09 +03:00
parent f96c1a2e44
commit cc363e7a6d
3 changed files with 379 additions and 156 deletions
+178 -152
View File
@@ -299,9 +299,12 @@ from sayistay_mcp_module.models import (
GenelKurulSearchRequest, GenelKurulSearchResponse, GenelKurulSearchRequest, GenelKurulSearchResponse,
TemyizKuruluSearchRequest, TemyizKuruluSearchResponse, TemyizKuruluSearchRequest, TemyizKuruluSearchResponse,
DaireSearchRequest, DaireSearchResponse, DaireSearchRequest, DaireSearchResponse,
SayistayDocumentMarkdown SayistayDocumentMarkdown,
SayistayUnifiedSearchRequest, SayistayUnifiedSearchResult,
SayistayUnifiedDocumentMarkdown, SayistayDecisionTypeEnum
) )
from sayistay_mcp_module.enums import DaireEnum, KamuIdaresiTuruEnum, WebKararKonusuEnum from sayistay_mcp_module.enums import DaireEnum, KamuIdaresiTuruEnum, WebKararKonusuEnum
from sayistay_mcp_module.unified_client import SayistayUnifiedClient
# KVKK Module Imports # KVKK Module Imports
from kvkk_mcp_module.client import KvkkApiClient from kvkk_mcp_module.client import KvkkApiClient
@@ -1055,6 +1058,7 @@ kik_client_instance = KikApiClient()
rekabet_client_instance = RekabetKurumuApiClient() rekabet_client_instance = RekabetKurumuApiClient()
bedesten_client_instance = BedestenApiClient() bedesten_client_instance = BedestenApiClient()
sayistay_client_instance = SayistayApiClient() sayistay_client_instance = SayistayApiClient()
sayistay_unified_client_instance = SayistayUnifiedClient()
kvkk_client_instance = KvkkApiClient() kvkk_client_instance = KvkkApiClient()
@@ -1843,194 +1847,215 @@ async def get_bedesten_document_markdown(
# --- MCP Tools for Sayıştay (Turkish Court of Accounts) --- # --- MCP Tools for Sayıştay (Turkish Court of Accounts) ---
@app.tool( # DEACTIVATED TOOL - Use search_sayistay_unified instead
description="Search Sayıştay Genel Kurul decisions for audit and accountability regulations", # @app.tool(
annotations={ # description="Search Sayıştay Genel Kurul decisions for audit and accountability regulations",
"readOnlyHint": True, # annotations={
"openWorldHint": True, # "readOnlyHint": True,
"idempotentHint": True # "openWorldHint": True,
} # "idempotentHint": True
) # }
async def search_sayistay_genel_kurul( # )
karar_no: str = Field("", description="Decision number to search for (e.g., '5415')"), # async def search_sayistay_genel_kurul(
karar_ek: str = Field("", description="Decision appendix number (max 99, e.g., '1')"), # karar_no: str = Field("", description="Decision number to search for (e.g., '5415')"),
karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY)"), # karar_ek: str = Field("", description="Decision appendix number (max 99, e.g., '1')"),
karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY)"), # karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY)"),
karar_tamami: str = Field("", description="Full text search"), # karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY)"),
start: int = Field(0, description="Starting record for pagination (0-based)"), # karar_tamami: str = Field("", description="Full text search"),
length: int = Field(10, description="Number of records per page (1-100)") # start: int = Field(0, description="Starting record for pagination (0-based)"),
) -> GenelKurulSearchResponse: # length: int = Field(10, description="Number of records per page (1-100)")
"""Search Sayıştay General Assembly decisions.""" # ) -> GenelKurulSearchResponse:
logger.info(f"Tool 'search_sayistay_genel_kurul' called with params: karar_no={karar_no}, karar_ek={karar_ek}, date_range={karar_tarih_baslangic}-{karar_tarih_bitis}, content={karar_tamami}") # """Search Sayıştay General Assembly decisions."""
# raise ValueError("This tool is deactivated. Use search_sayistay_unified instead.")
try:
search_request = GenelKurulSearchRequest( # DEACTIVATED TOOL - Use search_sayistay_unified instead
karar_no=karar_no, # @app.tool(
karar_ek=karar_ek, # description="Search Sayıştay Temyiz Kurulu decisions with chamber filtering and comprehensive criteria",
karar_tarih_baslangic=karar_tarih_baslangic, # annotations={
karar_tarih_bitis=karar_tarih_bitis, # "readOnlyHint": True,
karar_tamami=karar_tamami, # "openWorldHint": True,
start=start, # "idempotentHint": True
length=length # }
) # )
return await sayistay_client_instance.search_genel_kurul_decisions(search_request) # async def search_sayistay_temyiz_kurulu(
except Exception as e: # ilam_dairesi: DaireEnum = Field("ALL", description="Audit chamber selection"),
logger.exception("Error in tool 'search_sayistay_genel_kurul'") # yili: str = Field("", description="Year (YYYY)"),
raise # karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY)"),
# karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY)"),
# kamu_idaresi_turu: KamuIdaresiTuruEnum = Field("ALL", description="Public admin type"),
# ilam_no: str = Field("", description="Audit report number (İlam No, max 50 chars)"),
# dosya_no: str = Field("", description="File number for the case"),
# temyiz_tutanak_no: str = Field("", description="Appeals board meeting minutes number"),
# temyiz_karar: str = Field("", description="Appeals decision text"),
# web_karar_konusu: WebKararKonusuEnum = Field("ALL", description="Decision subject"),
# start: int = Field(0, description="Starting record for pagination (0-based)"),
# length: int = Field(10, description="Number of records per page (1-100)")
# ) -> TemyizKuruluSearchResponse:
# """Search Sayıştay Appeals Board decisions."""
# raise ValueError("This tool is deactivated. Use search_sayistay_unified instead.")
# DEACTIVATED TOOL - Use search_sayistay_unified instead
# @app.tool(
# description="Search Sayıştay Daire decisions with chamber filtering and subject categorization",
# annotations={
# "readOnlyHint": True,
# "openWorldHint": True,
# "idempotentHint": True
# }
# )
# async def search_sayistay_daire(
# yargilama_dairesi: DaireEnum = Field("ALL", description="Chamber selection"),
# karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY)"),
# karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY)"),
# ilam_no: str = Field("", description="Audit report number (İlam No, max 50 chars)"),
# kamu_idaresi_turu: KamuIdaresiTuruEnum = Field("ALL", description="Public admin type"),
# hesap_yili: str = Field("", description="Fiscal year"),
# web_karar_konusu: WebKararKonusuEnum = Field("ALL", description="Decision subject"),
# web_karar_metni: str = Field("", description="Decision text search"),
# start: int = Field(0, description="Starting record for pagination (0-based)"),
# length: int = Field(10, description="Number of records per page (1-100)")
# ) -> DaireSearchResponse:
# """Search Sayıştay Chamber decisions."""
# raise ValueError("This tool is deactivated. Use search_sayistay_unified instead.")
# DEACTIVATED TOOL - Use get_sayistay_document_unified instead
# @app.tool(
# description="Get Sayıştay Genel Kurul decision document in Markdown format",
# annotations={
# "readOnlyHint": True,
# "openWorldHint": False,
# "idempotentHint": True
# }
# )
# async def get_sayistay_genel_kurul_document_markdown(
# decision_id: str = Field(..., description="Decision ID from search_sayistay_genel_kurul results")
# ) -> SayistayDocumentMarkdown:
# """Get Sayıştay General Assembly decision as Markdown."""
# raise ValueError("This tool is deactivated. Use get_sayistay_document_unified instead.")
# DEACTIVATED TOOL - Use get_sayistay_document_unified instead
# @app.tool(
# description="Get Sayıştay Temyiz Kurulu decision document in Markdown format",
# annotations={
# "readOnlyHint": True,
# "openWorldHint": False,
# "idempotentHint": True
# }
# )
# async def get_sayistay_temyiz_kurulu_document_markdown(
# decision_id: str = Field(..., description="Decision ID from search_sayistay_temyiz_kurulu results")
# ) -> SayistayDocumentMarkdown:
# """Get Sayıştay Appeals Board decision as Markdown."""
# raise ValueError("This tool is deactivated. Use get_sayistay_document_unified instead.")
# DEACTIVATED TOOL - Use get_sayistay_document_unified instead
# @app.tool(
# description="Get Sayıştay Daire decision document in Markdown format",
# annotations={
# "readOnlyHint": True,
# "openWorldHint": False,
# "idempotentHint": True
# }
# )
# async def get_sayistay_daire_document_markdown(
# decision_id: str = Field(..., description="Decision ID from search_sayistay_daire results")
# ) -> SayistayDocumentMarkdown:
# """Get Sayıştay Chamber decision as Markdown."""
# raise ValueError("This tool is deactivated. Use get_sayistay_document_unified instead.")
# --- UNIFIED MCP Tools for Sayıştay (Turkish Court of Accounts) ---
@app.tool( @app.tool(
description="Search Sayıştay Temyiz Kurulu decisions with chamber filtering and comprehensive criteria", description="Search Sayıştay decisions unified across all three decision types (Genel Kurul, Temyiz Kurulu, Daire) with comprehensive filtering",
annotations={ annotations={
"readOnlyHint": True, "readOnlyHint": True,
"openWorldHint": True, "openWorldHint": True,
"idempotentHint": True "idempotentHint": True
} }
) )
async def search_sayistay_temyiz_kurulu( async def search_sayistay_unified(
ilam_dairesi: DaireEnum = Field("ALL", description="Audit chamber selection"), decision_type: SayistayDecisionTypeEnum = Field(..., description="Decision type: genel_kurul, temyiz_kurulu, or daire"),
yili: str = Field("", description="Year (YYYY)"),
karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY)"), # Common pagination parameters
karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY)"), start: int = Field(0, ge=0, description="Starting record for pagination (0-based)"),
kamu_idaresi_turu: KamuIdaresiTuruEnum = Field("ALL", description="Public admin type"), length: int = Field(10, ge=1, le=100, description="Number of records per page (1-100)"),
# Common search parameters
karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY format)"),
karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY format)"),
kamu_idaresi_turu: KamuIdaresiTuruEnum = Field("ALL", description="Public administration type filter"),
ilam_no: str = Field("", description="Audit report number (İlam No, max 50 chars)"), ilam_no: str = Field("", description="Audit report number (İlam No, max 50 chars)"),
dosya_no: str = Field("", description="File number for the case"), web_karar_konusu: WebKararKonusuEnum = Field("ALL", description="Decision subject category filter"),
temyiz_tutanak_no: str = Field("", description="Appeals board meeting minutes number"),
temyiz_karar: str = Field("", description="Appeals decision text"), # Genel Kurul specific parameters (ignored for other types)
web_karar_konusu: WebKararKonusuEnum = Field("ALL", description="Decision subject"), karar_no: str = Field("", description="Decision number (genel_kurul only)"),
start: int = Field(0, description="Starting record for pagination (0-based)"), karar_ek: str = Field("", description="Decision appendix number (genel_kurul only)"),
length: int = Field(10, description="Number of records per page (1-100)") karar_tamami: str = Field("", description="Full text search (genel_kurul only)"),
) -> TemyizKuruluSearchResponse:
"""Search Sayıştay Appeals Board decisions.""" # Temyiz Kurulu specific parameters (ignored for other types)
logger.info(f"Tool 'search_sayistay_temyiz_kurulu' called with params: chamber={ilam_dairesi}, year={yili}, admin_type={kamu_idaresi_turu}, subject={web_karar_konusu}") ilam_dairesi: DaireEnum = Field("ALL", description="Audit chamber selection (temyiz_kurulu only)"),
yili: str = Field("", description="Year (YYYY format, temyiz_kurulu only)"),
dosya_no: str = Field("", description="File number (temyiz_kurulu only)"),
temyiz_tutanak_no: str = Field("", description="Appeals board meeting minutes number (temyiz_kurulu only)"),
temyiz_karar: str = Field("", description="Appeals decision text search (temyiz_kurulu only)"),
# Daire specific parameters (ignored for other types)
yargilama_dairesi: DaireEnum = Field("ALL", description="Chamber selection (daire only)"),
hesap_yili: str = Field("", description="Account year (daire only)"),
web_karar_metni: str = Field("", description="Decision text search (daire only)")
) -> SayistayUnifiedSearchResult:
"""Search Sayıştay decisions across all three decision types with unified interface."""
logger.info(f"Tool 'search_sayistay_unified' called with decision_type={decision_type}")
try: try:
search_request = TemyizKuruluSearchRequest( search_request = SayistayUnifiedSearchRequest(
ilam_dairesi=ilam_dairesi, decision_type=decision_type,
yili=yili, start=start,
length=length,
karar_tarih_baslangic=karar_tarih_baslangic, karar_tarih_baslangic=karar_tarih_baslangic,
karar_tarih_bitis=karar_tarih_bitis, karar_tarih_bitis=karar_tarih_bitis,
kamu_idaresi_turu=kamu_idaresi_turu, kamu_idaresi_turu=kamu_idaresi_turu,
ilam_no=ilam_no, ilam_no=ilam_no,
web_karar_konusu=web_karar_konusu,
karar_no=karar_no,
karar_ek=karar_ek,
karar_tamami=karar_tamami,
ilam_dairesi=ilam_dairesi,
yili=yili,
dosya_no=dosya_no, dosya_no=dosya_no,
temyiz_tutanak_no=temyiz_tutanak_no, temyiz_tutanak_no=temyiz_tutanak_no,
temyiz_karar=temyiz_karar, temyiz_karar=temyiz_karar,
web_karar_konusu=web_karar_konusu,
start=start,
length=length
)
return await sayistay_client_instance.search_temyiz_kurulu_decisions(search_request)
except Exception as e:
logger.exception("Error in tool 'search_sayistay_temyiz_kurulu'")
raise
@app.tool(
description="Search Sayıştay Daire decisions with chamber filtering and subject categorization",
annotations={
"readOnlyHint": True,
"openWorldHint": True,
"idempotentHint": True
}
)
async def search_sayistay_daire(
yargilama_dairesi: DaireEnum = Field("ALL", description="Chamber selection"),
karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY)"),
karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY)"),
ilam_no: str = Field("", description="Audit report number (İlam No, max 50 chars)"),
kamu_idaresi_turu: KamuIdaresiTuruEnum = Field("ALL", description="Public admin type"),
hesap_yili: str = Field("", description="Fiscal year"),
web_karar_konusu: WebKararKonusuEnum = Field("ALL", description="Decision subject"),
web_karar_metni: str = Field("", description="Decision text search"),
start: int = Field(0, description="Starting record for pagination (0-based)"),
length: int = Field(10, description="Number of records per page (1-100)")
) -> DaireSearchResponse:
"""Search Sayıştay Chamber decisions."""
logger.info(f"Tool 'search_sayistay_daire' called with params: chamber={yargilama_dairesi}, admin_type={kamu_idaresi_turu}, subject={web_karar_konusu}, content={web_karar_metni}")
try:
search_request = DaireSearchRequest(
yargilama_dairesi=yargilama_dairesi, yargilama_dairesi=yargilama_dairesi,
karar_tarih_baslangic=karar_tarih_baslangic,
karar_tarih_bitis=karar_tarih_bitis,
ilam_no=ilam_no,
kamu_idaresi_turu=kamu_idaresi_turu,
hesap_yili=hesap_yili, hesap_yili=hesap_yili,
web_karar_konusu=web_karar_konusu, web_karar_metni=web_karar_metni
web_karar_metni=web_karar_metni,
start=start,
length=length
) )
return await sayistay_client_instance.search_daire_decisions(search_request) return await sayistay_unified_client_instance.search_unified(search_request)
except Exception as e: except Exception as e:
logger.exception("Error in tool 'search_sayistay_daire'") logger.exception("Error in tool 'search_sayistay_unified'")
raise raise
@app.tool( @app.tool(
description="Get Sayıştay Genel Kurul decision document in Markdown format", description="Get Sayıştay decision document in Markdown format for any decision type",
annotations={ annotations={
"readOnlyHint": True, "readOnlyHint": True,
"openWorldHint": False, "openWorldHint": False,
"idempotentHint": True "idempotentHint": True
} }
) )
async def get_sayistay_genel_kurul_document_markdown( async def get_sayistay_document_unified(
decision_id: str = Field(..., description="Decision ID from search_sayistay_genel_kurul results") decision_id: str = Field(..., description="Decision ID from search_sayistay_unified results"),
) -> SayistayDocumentMarkdown: decision_type: SayistayDecisionTypeEnum = Field(..., description="Decision type: genel_kurul, temyiz_kurulu, or daire")
"""Get Sayıştay General Assembly decision as Markdown.""" ) -> SayistayUnifiedDocumentMarkdown:
logger.info(f"Tool 'get_sayistay_genel_kurul_document_markdown' called for ID: {decision_id}") """Get Sayıştay decision document as Markdown for any decision type."""
logger.info(f"Tool 'get_sayistay_document_unified' called for ID: {decision_id}, type: {decision_type}")
if not decision_id or not decision_id.strip(): if not decision_id or not decision_id.strip():
raise ValueError("Decision ID must be a non-empty string.") raise ValueError("Decision ID must be a non-empty string.")
try: try:
return await sayistay_client_instance.get_document_as_markdown(decision_id, "genel_kurul") return await sayistay_unified_client_instance.get_document_unified(decision_id, decision_type)
except Exception as e: except Exception as e:
logger.exception("Error in tool 'get_sayistay_genel_kurul_document_markdown'") logger.exception("Error in tool 'get_sayistay_document_unified'")
raise
@app.tool(
description="Get Sayıştay Temyiz Kurulu decision document in Markdown format",
annotations={
"readOnlyHint": True,
"openWorldHint": False,
"idempotentHint": True
}
)
async def get_sayistay_temyiz_kurulu_document_markdown(
decision_id: str = Field(..., description="Decision ID from search_sayistay_temyiz_kurulu results")
) -> SayistayDocumentMarkdown:
"""Get Sayıştay Appeals Board decision as Markdown."""
logger.info(f"Tool 'get_sayistay_temyiz_kurulu_document_markdown' called for ID: {decision_id}")
if not decision_id or not decision_id.strip():
raise ValueError("Decision ID must be a non-empty string.")
try:
return await sayistay_client_instance.get_document_as_markdown(decision_id, "temyiz_kurulu")
except Exception as e:
logger.exception("Error in tool 'get_sayistay_temyiz_kurulu_document_markdown'")
raise
@app.tool(
description="Get Sayıştay Daire decision document in Markdown format",
annotations={
"readOnlyHint": True,
"openWorldHint": False,
"idempotentHint": True
}
)
async def get_sayistay_daire_document_markdown(
decision_id: str = Field(..., description="Decision ID from search_sayistay_daire results")
) -> SayistayDocumentMarkdown:
"""Get Sayıştay Chamber decision as Markdown."""
logger.info(f"Tool 'get_sayistay_daire_document_markdown' called for ID: {decision_id}")
if not decision_id or not decision_id.strip():
raise ValueError("Decision ID must be a non-empty string.")
try:
return await sayistay_client_instance.get_document_as_markdown(decision_id, "daire")
except Exception as e:
logger.exception("Error in tool 'get_sayistay_daire_document_markdown'")
raise raise
# --- Application Shutdown Handling --- # --- Application Shutdown Handling ---
@@ -2056,6 +2081,7 @@ def perform_cleanup():
globals().get('rekabet_client_instance'), globals().get('rekabet_client_instance'),
globals().get('bedesten_client_instance'), globals().get('bedesten_client_instance'),
globals().get('sayistay_client_instance'), globals().get('sayistay_client_instance'),
globals().get('sayistay_unified_client_instance'),
globals().get('kvkk_client_instance') globals().get('kvkk_client_instance')
] ]
async def close_all_clients_async(): async def close_all_clients_async():
+64 -4
View File
@@ -1,9 +1,16 @@
# sayistay_mcp_module/models.py # sayistay_mcp_module/models.py
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from typing import Optional, List, Union from typing import Optional, List, Union, Dict, Any
from enum import Enum
from .enums import DaireEnum, KamuIdaresiTuruEnum, WebKararKonusuEnum from .enums import DaireEnum, KamuIdaresiTuruEnum, WebKararKonusuEnum
# --- Unified Enums ---
class SayistayDecisionTypeEnum(str, Enum):
GENEL_KURUL = "genel_kurul"
TEMYIZ_KURULU = "temyiz_kurulu"
DAIRE = "daire"
# ============================================================================ # ============================================================================
# Genel Kurul (General Assembly) Models # Genel Kurul (General Assembly) Models
# ============================================================================ # ============================================================================
@@ -155,6 +162,59 @@ class SayistayDocumentMarkdown(BaseModel):
decision_id: str = Field(..., description="Unique decision identifier") decision_id: str = Field(..., description="Unique decision identifier")
decision_type: str = Field(..., description="Value") decision_type: str = Field(..., description="Value")
source_url: str = Field(..., description="Original URL where the document was retrieved") source_url: str = Field(..., description="Original URL where the document was retrieved")
markdown_content: str = Field("", description="Full decision text converted to Markdown format") markdown_content: Optional[str] = Field(None, description="Full decision text converted to Markdown format")
retrieval_date: str = Field("", description="Date when document was retrieved (ISO format)") retrieval_date: Optional[str] = Field(None, description="Date when document was retrieved (ISO format)")
error_message: str = Field("", description="Error message if document retrieval failed") error_message: Optional[str] = Field(None, description="Error message if document retrieval failed")
# ============================================================================
# Unified Models
# ============================================================================
class SayistayUnifiedSearchRequest(BaseModel):
"""Unified search request for all Sayıştay decision types."""
decision_type: SayistayDecisionTypeEnum = Field(..., description="Decision type: genel_kurul, temyiz_kurulu, or daire")
# Common pagination parameters
start: int = Field(0, ge=0, description="Starting record for pagination (0-based)")
length: int = Field(10, ge=1, le=100, description="Number of records per page (1-100)")
# Common search parameters
karar_tarih_baslangic: str = Field("", description="Start date (DD.MM.YYYY format)")
karar_tarih_bitis: str = Field("", description="End date (DD.MM.YYYY format)")
kamu_idaresi_turu: KamuIdaresiTuruEnum = Field("ALL", description="Public administration type filter")
ilam_no: str = Field("", description="Audit report number (İlam No, max 50 chars)")
web_karar_konusu: WebKararKonusuEnum = Field("ALL", description="Decision subject category filter")
# Genel Kurul specific parameters (ignored for other types)
karar_no: str = Field("", description="Decision number (genel_kurul only)")
karar_ek: str = Field("", description="Decision appendix number (genel_kurul only)")
karar_tamami: str = Field("", description="Full text search (genel_kurul only)")
# Temyiz Kurulu specific parameters (ignored for other types)
ilam_dairesi: DaireEnum = Field("ALL", description="Audit chamber selection (temyiz_kurulu only)")
yili: str = Field("", description="Year (YYYY format, temyiz_kurulu only)")
dosya_no: str = Field("", description="File number (temyiz_kurulu only)")
temyiz_tutanak_no: str = Field("", description="Appeals board meeting minutes number (temyiz_kurulu only)")
temyiz_karar: str = Field("", description="Appeals decision text search (temyiz_kurulu only)")
# Daire specific parameters (ignored for other types)
yargilama_dairesi: DaireEnum = Field("ALL", description="Chamber selection (daire only)")
hesap_yili: str = Field("", description="Account year (daire only)")
web_karar_metni: str = Field("", description="Decision text search (daire only)")
class SayistayUnifiedSearchResult(BaseModel):
"""Unified search result containing decisions from any Sayıştay decision type."""
decision_type: SayistayDecisionTypeEnum = Field(..., description="Type of decisions returned")
decisions: List[Dict[str, Any]] = Field(default_factory=list, description="Decision list (structure varies by type)")
total_records: int = Field(0, description="Total number of records found")
total_filtered: int = Field(0, description="Number of records after filtering")
draw: int = Field(1, description="DataTables draw counter")
class SayistayUnifiedDocumentMarkdown(BaseModel):
"""Unified document model for all Sayıştay decision types."""
decision_type: SayistayDecisionTypeEnum = Field(..., description="Type of document")
decision_id: str = Field(..., description="Decision ID")
source_url: str = Field(..., description="Source URL of the document")
document_data: Dict[str, Any] = Field(default_factory=dict, description="Document content and metadata")
markdown_content: Optional[str] = Field(None, description="Markdown content")
error_message: Optional[str] = Field(None, description="Error message if retrieval failed")
+137
View File
@@ -0,0 +1,137 @@
# sayistay_mcp_module/unified_client.py
# Unified client for all three Sayıştay decision types
import logging
from typing import Optional, Dict, Any
from urllib.parse import urlparse
from .models import (
SayistayUnifiedSearchRequest,
SayistayUnifiedSearchResult,
SayistayUnifiedDocumentMarkdown,
SayistayDecisionTypeEnum,
GenelKurulSearchRequest,
TemyizKuruluSearchRequest,
DaireSearchRequest
)
from .client import SayistayApiClient
logger = logging.getLogger(__name__)
class SayistayUnifiedClient:
"""Unified client that handles all three Sayıştay decision types."""
def __init__(self, request_timeout: float = 60.0):
self.client = SayistayApiClient(request_timeout)
async def search_unified(self, params: SayistayUnifiedSearchRequest) -> SayistayUnifiedSearchResult:
"""Unified search that routes to appropriate search method based on decision_type."""
if params.decision_type == SayistayDecisionTypeEnum.GENEL_KURUL:
# Convert to genel kurul request
genel_kurul_params = GenelKurulSearchRequest(
karar_no=params.karar_no,
karar_ek=params.karar_ek,
karar_tarih_baslangic=params.karar_tarih_baslangic,
karar_tarih_bitis=params.karar_tarih_bitis,
karar_tamami=params.karar_tamami,
start=params.start,
length=params.length
)
result = await self.client.search_genel_kurul_decisions(genel_kurul_params)
# Convert to unified format
decisions_list = [decision.model_dump() for decision in result.decisions]
return SayistayUnifiedSearchResult(
decision_type=SayistayDecisionTypeEnum.GENEL_KURUL,
decisions=decisions_list,
total_records=result.total_records,
total_filtered=result.total_filtered,
draw=result.draw
)
elif params.decision_type == SayistayDecisionTypeEnum.TEMYIZ_KURULU:
# Convert to temyiz kurulu request
temyiz_params = TemyizKuruluSearchRequest(
ilam_dairesi=params.ilam_dairesi,
yili=params.yili,
karar_tarih_baslangic=params.karar_tarih_baslangic,
karar_tarih_bitis=params.karar_tarih_bitis,
kamu_idaresi_turu=params.kamu_idaresi_turu,
ilam_no=params.ilam_no,
dosya_no=params.dosya_no,
temyiz_tutanak_no=params.temyiz_tutanak_no,
temyiz_karar=params.temyiz_karar,
web_karar_konusu=params.web_karar_konusu,
start=params.start,
length=params.length
)
result = await self.client.search_temyiz_kurulu_decisions(temyiz_params)
# Convert to unified format
decisions_list = [decision.model_dump() for decision in result.decisions]
return SayistayUnifiedSearchResult(
decision_type=SayistayDecisionTypeEnum.TEMYIZ_KURULU,
decisions=decisions_list,
total_records=result.total_records,
total_filtered=result.total_filtered,
draw=result.draw
)
elif params.decision_type == SayistayDecisionTypeEnum.DAIRE:
# Convert to daire request
daire_params = DaireSearchRequest(
yargilama_dairesi=params.yargilama_dairesi,
karar_tarih_baslangic=params.karar_tarih_baslangic,
karar_tarih_bitis=params.karar_tarih_bitis,
ilam_no=params.ilam_no,
kamu_idaresi_turu=params.kamu_idaresi_turu,
hesap_yili=params.hesap_yili,
web_karar_konusu=params.web_karar_konusu,
web_karar_metni=params.web_karar_metni,
start=params.start,
length=params.length
)
result = await self.client.search_daire_decisions(daire_params)
# Convert to unified format
decisions_list = [decision.model_dump() for decision in result.decisions]
return SayistayUnifiedSearchResult(
decision_type=SayistayDecisionTypeEnum.DAIRE,
decisions=decisions_list,
total_records=result.total_records,
total_filtered=result.total_filtered,
draw=result.draw
)
else:
raise ValueError(f"Unsupported decision type: {params.decision_type}")
async def get_document_unified(self, decision_id: str, decision_type: SayistayDecisionTypeEnum) -> SayistayUnifiedDocumentMarkdown:
"""Unified document retrieval for all Sayıştay decision types."""
# Convert enum to string for backend client
decision_type_str = decision_type.value
# Use existing client method
result = await self.client.get_document_as_markdown(decision_id, decision_type_str)
return SayistayUnifiedDocumentMarkdown(
decision_type=decision_type,
decision_id=result.decision_id,
source_url=result.source_url,
document_data=result.model_dump(),
markdown_content=result.markdown_content,
error_message=result.error_message
)
async def close_client_session(self):
"""Close the underlying client session."""
if hasattr(self.client, 'close_client_session'):
await self.client.close_client_session()