Skip to content

Commit 4093f30

Browse files
committed
fix: enhance CSV ticket handling and update LLM backend initialization
Signed-off-by: Andre Bossard <anbossar@microsoft.com>
1 parent 1416147 commit 4093f30

4 files changed

Lines changed: 47 additions & 29 deletions

File tree

backend/agents.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def _env_int(name: str, default: int) -> int:
5656

5757
# Local CSV service
5858
from csv_data import get_csv_ticket_service
59-
6059
from langchain_core.tools import StructuredTool
6160

6261
# Third-party - LangGraph
@@ -186,10 +185,11 @@ def __init__(self):
186185
"""
187186
Initialize the agent service.
188187
189-
Uses OpenAI when OPENAI_API_KEY is set, otherwise falls back
190-
to LiteLLM (supports GitHub Copilot, Ollama, etc.).
188+
Defaults to LiteLLM with GitHub Copilot backend.
189+
Set AGENT_BACKEND=openai to force OpenAI SDK (requires OPENAI_API_KEY).
191190
"""
192-
if OPENAI_API_KEY:
191+
force_openai = os.getenv("AGENT_BACKEND", "").lower() == "openai"
192+
if force_openai and OPENAI_API_KEY:
193193
from langchain_openai import ChatOpenAI
194194
self.llm = ChatOpenAI(
195195
model=OPENAI_MODEL,

backend/app.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,19 @@
3737
# CSV ticket service
3838
from csv_data import Ticket, get_csv_ticket_service
3939

40+
# FastMCP client for direct ticket MCP calls (no AI)
41+
from fastmcp import Client as MCPClient
42+
4043
# KBA Drafter
4144
from kba_exceptions import (
4245
DraftNotFoundError,
4346
DuplicateKBADraftError,
4447
InvalidLLMOutputError,
4548
InvalidStatusError,
49+
LLMAuthenticationError,
50+
LLMRateLimitError,
51+
LLMTimeoutError,
52+
LLMUnavailableError,
4653
PublishFailedError,
4754
TicketNotFoundError,
4855
)
@@ -53,15 +60,6 @@
5360
KBADraftUpdate,
5461
KBAPublishRequest,
5562
)
56-
from kba_exceptions import (
57-
LLMTimeoutError,
58-
LLMUnavailableError,
59-
LLMRateLimitError,
60-
LLMAuthenticationError,
61-
)
62-
63-
# FastMCP client for direct ticket MCP calls (no AI)
64-
from fastmcp import Client as MCPClient
6563
from mcp_handler import handle_mcp_request
6664
from operations import (
6765
CSV_TICKET_FIELDS,
@@ -111,8 +109,9 @@
111109
@app.before_serving
112110
async def startup():
113111
"""Initialize scheduler on application startup"""
114-
from scheduler import start_scheduler
115112
import logging
113+
114+
from scheduler import start_scheduler
116115

117116
logger = logging.getLogger(__name__)
118117
logger.info("Starting auto-generation scheduler...")
@@ -127,8 +126,9 @@ async def startup():
127126
@app.after_serving
128127
async def shutdown():
129128
"""Cleanup scheduler on application shutdown"""
130-
from scheduler import stop_scheduler
131129
import logging
130+
131+
from scheduler import stop_scheduler
132132

133133
logger = logging.getLogger(__name__)
134134
logger.info("Stopping auto-generation scheduler...")
@@ -585,6 +585,12 @@ async def get_qa_tickets():
585585
if _csv_data_path.exists():
586586
_csv_loaded = _csv_ticket_service.load_csv(_csv_data_path)
587587
print(f"📊 Loaded {_csv_loaded} tickets from CSV")
588+
else:
589+
print(
590+
f"⚠️ CSV data file not found: {_csv_data_path.resolve()}\n"
591+
f" Ticket features will be unavailable.\n"
592+
f" To fix: place your BMC Remedy/ITSM CSV export at csv/data.csv"
593+
)
588594

589595

590596
@app.route("/api/csv-tickets/fields", methods=["GET"])
@@ -974,6 +980,7 @@ async def rest_kba_publish_draft(draft_id: str):
974980
async def rest_kba_list_drafts():
975981
"""REST wrapper: list KBA drafts with filtering."""
976982
from operations import op_kba_list_drafts
983+
977984
# Parse query parameters
978985
filters = KBADraftFilter(
979986
status=request.args.get("status"),
@@ -1039,8 +1046,8 @@ async def rest_kba_get_auto_gen_settings():
10391046
@app.route("/api/kba/auto-gen/settings", methods=["PATCH"])
10401047
async def rest_kba_update_auto_gen_settings():
10411048
"""REST wrapper: update auto-generation settings."""
1042-
from operations import op_kba_update_auto_gen_settings
10431049
from auto_gen_models import AutoGenSettingsUpdate
1050+
from operations import op_kba_update_auto_gen_settings
10441051

10451052
data = await request.get_json()
10461053
updates = AutoGenSettingsUpdate(**data)

backend/llm_service.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,13 @@
3030
import os
3131
from typing import Any, Optional, Type
3232

33-
from pydantic import BaseModel
34-
3533
from kba_exceptions import (
36-
LLMUnavailableError,
37-
LLMTimeoutError,
34+
LLMAuthenticationError,
3835
LLMRateLimitError,
39-
LLMAuthenticationError
36+
LLMTimeoutError,
37+
LLMUnavailableError,
4038
)
39+
from pydantic import BaseModel
4140

4241
logger = logging.getLogger(__name__)
4342

@@ -89,7 +88,8 @@ def __init__(
8988
"""
9089
self.timeout = timeout
9190

92-
# Determine backend: LiteLLM is the default, OpenAI only when forced
91+
# Determine backend: LiteLLM with Copilot is the default.
92+
# OpenAI only when explicitly forced via backend="openai".
9393
resolved_api_key = api_key or OPENAI_API_KEY
9494
if backend == "openai":
9595
self._backend = "openai"
@@ -112,9 +112,9 @@ def __init__(
112112
client_kwargs["base_url"] = self.base_url
113113
self._client = AsyncOpenAI(**client_kwargs)
114114
else:
115-
# LiteLLM backend
115+
# LiteLLM backend — always default to Copilot model
116116
self.api_key = resolved_api_key or None
117-
self.model = model or (OPENAI_MODEL if resolved_api_key else LITELLM_MODEL)
117+
self.model = model or LITELLM_MODEL
118118
self.base_url = base_url or OPENAI_BASE_URL or None
119119
self._client = None
120120
# Build fallback chain: primary model + configured fallbacks (deduplicated)
@@ -295,9 +295,9 @@ def _handle_openai_error(self, error: Exception) -> Exception:
295295
from openai import (
296296
APIConnectionError,
297297
APITimeoutError,
298-
RateLimitError,
299298
AuthenticationError,
300-
BadRequestError
299+
BadRequestError,
300+
RateLimitError,
301301
)
302302

303303
if isinstance(error, APITimeoutError):

backend/operations.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ def _get_kba_session() -> Session:
8585
global _kba_db_engine, _kba_session
8686
if _kba_db_engine is None:
8787
from pathlib import Path
88-
from kba_models import KBADraftTable, KBAAuditLog
88+
8989
from auto_gen_models import AutoGenSettingsTable
90+
from kba_models import KBAAuditLog, KBADraftTable
9091
from sqlmodel import SQLModel
9192

9293
db_path = Path(__file__).parent / "data" / "kba.db"
@@ -162,8 +163,18 @@ def _ensure_csv_loaded() -> None:
162163
if default_csv_path.exists():
163164
try:
164165
_csv_service.load_csv(default_csv_path)
165-
except Exception:
166-
pass
166+
except Exception as exc:
167+
import logging
168+
logging.getLogger(__name__).warning(
169+
"Failed to load CSV data from %s: %s", default_csv_path, exc
170+
)
171+
else:
172+
import logging
173+
logging.getLogger(__name__).warning(
174+
"CSV data file not found: %s — ticket operations will return empty results. "
175+
"Place your BMC Remedy/ITSM CSV export at csv/data.csv to enable ticket features.",
176+
default_csv_path.resolve(),
177+
)
167178
_csv_loaded = True
168179

169180

0 commit comments

Comments
 (0)