Skip to content

Commit eafc8c4

Browse files
WIP
1 parent 49944ca commit eafc8c4

10 files changed

Lines changed: 192 additions & 200 deletions

File tree

src/blockether_catalyst/integrations/agno/AgnoOsASGIModule.py

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ class MCPConfig(BaseModel):
100100

101101
model_config = ConfigDict(arbitrary_types_allowed=True)
102102

103-
workflow: "Workflow" = Field(..., description="The MCP workflow to use")
104103
name: str = Field(description="Name of the MCP application")
105104
tools: List[Tool] = Field(default_factory=list, description="List of tools to register with MCP")
106105
resources: List[Resource] = Field(default_factory=list, description="List of resources for MCP")
@@ -191,6 +190,8 @@ def mount(self, app: FastAPI, router: APIRouter) -> None:
191190
for tool in self.mcp.tools:
192191
mcp.add_tool(tool)
193192

193+
app.mount("/mcp", mcp.http_app("/", stateless_http=True, transport="sse"))
194+
194195
if not self.chat or not self.chat.assistant:
195196
raise ValueError("Chat configuration or assistant is not properly set")
196197

@@ -232,13 +233,13 @@ async def chat_interface(request: Request) -> HTMLResponse:
232233

233234
if self.workflows:
234235
session_type = "workflow"
235-
executor_id = self.workflows[0].id if hasattr(self.workflows[0], 'id') else ""
236+
executor_id = self.workflows[0].id if hasattr(self.workflows[0], "id") else ""
236237
elif self.agents:
237238
session_type = "agent"
238-
executor_id = self.agents[0].id if hasattr(self.agents[0], 'id') else ""
239+
executor_id = self.agents[0].id if hasattr(self.agents[0], "id") else ""
239240
elif self.teams:
240241
session_type = "team"
241-
executor_id = self.teams[0].id if hasattr(self.teams[0], 'id') else ""
242+
executor_id = self.teams[0].id if hasattr(self.teams[0], "id") else ""
242243

243244
# Create the response using render_template which returns a TemplateResponse
244245
response = self.render_template(
@@ -744,7 +745,7 @@ async def executor_runs(request: Request) -> Dict[str, Any]:
744745
return {
745746
"error": "Missing required field: 'message'",
746747
"status": "error",
747-
"code": 400
748+
"code": 400,
748749
}
749750

750751
# Get the runner from the assistant config
@@ -807,64 +808,93 @@ async def executor_runs(request: Request) -> Dict[str, Any]:
807808
}
808809

809810
@router_os.get("/sessions/{session_id}/runs", include_in_schema=False)
810-
async def get_session_runs(session_id: str) -> List[Dict[str, Any]]:
811+
async def get_session_runs(session_id: str, request: Request) -> List[Dict[str, Any]]:
811812
"""Get all runs for a session."""
812813
try:
813814
# Get the runner from the assistant config
814815
runner = self.chat.assistant.runner
815-
816+
816817
# Check if the runner has a database
817-
if not hasattr(runner, 'db') or runner.db is None:
818+
if not hasattr(runner, "db") or runner.db is None:
818819
logger.debug(f"No database configured for runner, returning empty list for session {session_id}")
819820
return []
820-
821+
822+
# Get session type from query params if provided
823+
session_type = request.query_params.get("type")
824+
821825
# Get the session from the database - try different session types
822826
session = None
823-
for session_type in ["workflow", "agent", "team"]:
827+
if session_type:
828+
# If type is specified, only try that type
824829
try:
825830
session = runner.db.get_session(session_id, session_type)
826-
if session:
827-
break
828831
except Exception:
829-
continue
832+
pass
833+
else:
834+
# Otherwise try all types
835+
for st in ["agent", "workflow", "team"]:
836+
try:
837+
session = runner.db.get_session(session_id, st)
838+
if session:
839+
break
840+
except Exception:
841+
continue
830842

831843
if not session:
832844
logger.debug(f"No session found for {session_id}")
833845
return []
834-
846+
835847
# Extract runs from the session
836848
runs = []
837-
if hasattr(session, 'agent_runs'):
849+
if hasattr(session, "agent_runs") and session.agent_runs:
838850
# For agent sessions
839851
for run in session.agent_runs:
840-
runs.append({
841-
"run_id": run.run_id,
842-
"session_id": session_id,
843-
"input": run.user_message,
844-
"output": run.response,
845-
"created_at": run.created_at.isoformat() if hasattr(run.created_at, 'isoformat') else str(run.created_at),
846-
})
847-
elif hasattr(session, 'workflow_runs'):
852+
runs.append(
853+
{
854+
"run_id": run.run_id,
855+
"session_id": session_id,
856+
"input": getattr(run, "user_message", getattr(run, "input", "")),
857+
"output": getattr(run, "response", getattr(run, "output", "")),
858+
"created_at": (
859+
run.created_at.isoformat()
860+
if hasattr(run.created_at, "isoformat")
861+
else str(run.created_at)
862+
),
863+
}
864+
)
865+
elif hasattr(session, "workflow_runs") and session.workflow_runs:
848866
# For workflow sessions
849867
for run in session.workflow_runs:
850-
runs.append({
851-
"run_id": run.run_id,
852-
"session_id": session_id,
853-
"input": run.input,
854-
"output": run.output,
855-
"created_at": run.created_at.isoformat() if hasattr(run.created_at, 'isoformat') else str(run.created_at),
856-
})
857-
elif hasattr(session, 'team_runs'):
868+
runs.append(
869+
{
870+
"run_id": run.run_id,
871+
"session_id": session_id,
872+
"input": getattr(run, "input", getattr(run, "user_message", "")),
873+
"output": getattr(run, "output", getattr(run, "response", "")),
874+
"created_at": (
875+
run.created_at.isoformat()
876+
if hasattr(run.created_at, "isoformat")
877+
else str(run.created_at)
878+
),
879+
}
880+
)
881+
elif hasattr(session, "team_runs") and session.team_runs:
858882
# For team sessions
859883
for run in session.team_runs:
860-
runs.append({
861-
"run_id": run.run_id,
862-
"session_id": session_id,
863-
"input": run.input,
864-
"output": run.output,
865-
"created_at": run.created_at.isoformat() if hasattr(run.created_at, 'isoformat') else str(run.created_at),
866-
})
867-
884+
runs.append(
885+
{
886+
"run_id": run.run_id,
887+
"session_id": session_id,
888+
"input": getattr(run, "input", getattr(run, "user_message", "")),
889+
"output": getattr(run, "output", getattr(run, "response", "")),
890+
"created_at": (
891+
run.created_at.isoformat()
892+
if hasattr(run.created_at, "isoformat")
893+
else str(run.created_at)
894+
),
895+
}
896+
)
897+
868898
logger.debug(f"Retrieved {len(runs)} runs for session {session_id}")
869899
return runs
870900

src/blockether_catalyst/knowledge/KnowledgeExtractionCore.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,12 +1060,10 @@ async def classify_single_chunk(chunk: KnowledgeChunk) -> KnowledgeChunk:
10601060
"""Classify a single chunk's semantic type - MANDATORY."""
10611061
# Handle empty or whitespace-only chunks
10621062
if not chunk.text or not chunk.text.strip():
1063-
logger.warning(
1064-
f"Chunk {chunk.index} is empty, assigning 'general' semantic type"
1065-
)
1063+
logger.warning(f"Chunk {chunk.index} is empty, assigning 'general' semantic type")
10661064
chunk.semantic_types = ["general"]
10671065
return chunk
1068-
1066+
10691067
result = await self.calls.chunk_content_classification_call.execute(
10701068
chunk_text=chunk.text,
10711069
document_name=doc_result.document_filename,

src/blockether_catalyst/knowledge/KnowledgeSearchCore.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
ImageInfo,
2525
KnowledgeSearchResult,
2626
LinkedKnowledge,
27+
LinkedTermInfo,
2728
NormalizedSearchResult,
2829
SearchResult,
2930
SearchResultMetadata,
@@ -314,7 +315,12 @@ def search(
314315
# Enhance search results with term analysis and boosting
315316
# The function now handles efficient top-k selection internally
316317
enhanced_results = self._enhance_search_results(
317-
search_results, query, top_terms, max_depth, max_cooccurrences, k * 2 # Get more for filtering
318+
search_results,
319+
query,
320+
top_terms,
321+
max_depth,
322+
max_cooccurrences,
323+
k * 2, # Get more for filtering
318324
)
319325

320326
# Filter enhanced results based on acronym/keyword matches
@@ -765,12 +771,13 @@ def _convert_to_term_info(self, term: TermWithLinks, link_limit: int) -> Optiona
765771
linked_term = self._resolve_term(link.link_to)
766772
if linked_term:
767773
linked_terms.append(
768-
TermInfo(
774+
LinkedTermInfo(
769775
term=linked_term.term,
770776
meaning=linked_term.meaning[:600] if linked_term.meaning else None,
771777
term_type=linked_term.type,
772778
link_score=link.score,
773779
total_times_occurred_in_knowledgebase=linked_term.total,
780+
linked_terms=[], # Usually empty to prevent deep nesting
774781
)
775782
)
776783

@@ -865,9 +872,7 @@ def get_extraction_details(self) -> Dict[str, Any]:
865872
if not self._linked_knowledge:
866873
return {}
867874

868-
return self._linked_knowledge.get_extraction_details(
869-
base_url=self._resources_base_url or ""
870-
)
875+
return self._linked_knowledge.get_extraction_details(base_url=self._resources_base_url or "")
871876

872877
def persist(self, path: Optional[Union[str, Path]] = None) -> None:
873878
"""

src/blockether_catalyst/knowledge/KnowledgeTypes.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,9 +566,8 @@ class TermInfo(TypedPydanticModel):
566566
term: str = Field(description="The term text")
567567
meaning: Optional[str] = Field(default=None, description="Meaning of the term")
568568
term_type: Optional[str] = Field(default=None, description="Type of term (e.g., acronym, keyword)")
569-
link_score: Optional[float] = Field(default=None, description="Score of the link to this term")
570569
total_times_occurred_in_knowledgebase: Optional[int] = Field(default=None, description="Total occurrences")
571-
linked_terms: List["TermInfo"] = Field(default_factory=list, description="Linked terms")
570+
linked_terms: List["LinkedTermInfo"] = Field(default_factory=list, description="Terms linked from this term")
572571

573572
def markdown(self) -> str:
574573
"""Generate markdown for a term."""
@@ -598,6 +597,15 @@ def markdown(self) -> str:
598597
return "\n".join(lines)
599598

600599

600+
class LinkedTermInfo(TermInfo):
601+
"""Information about a term that is linked from another term (extends TermInfo with link_score)."""
602+
603+
link_score: float = Field(description="Score of the link to this term (strength of relationship, 0.0-1.0)")
604+
linked_terms: List["LinkedTermInfo"] = Field(
605+
default_factory=list, description="Nested linked terms (usually empty)"
606+
)
607+
608+
601609
class ImageInfo(TypedPydanticModel):
602610
"""Information about an image."""
603611

src/blockether_catalyst/knowledge/PDFKnowledgeExtractor.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,12 @@ def _process_page(
139139
base_text = page_without_tables.extract_text(**self._text_extraction_settings.model_dump()) or ""
140140

141141
# Extract image
142-
images = self._extract_images_from_page(page, context=base_text, current_document=current_document, current_document_path=current_document_path)
142+
images = self._extract_images_from_page(
143+
page,
144+
context=base_text,
145+
current_document=current_document,
146+
current_document_path=current_document_path,
147+
)
143148

144149
# Fix hyphenated line breaks immediately after extraction
145150
base_text = self._fix_hyphenated_line_breaks(base_text)
@@ -256,9 +261,7 @@ def _extract_tables_from_page(
256261
tables.append(pdf_table)
257262

258263
except Exception as e:
259-
self._logger.warning(
260-
f"[{current_document}] Error extracting table on page {page.page_number}: {e}"
261-
)
264+
self._logger.warning(f"[{current_document}] Error extracting table on page {page.page_number}: {e}")
262265

263266
return tables
264267

0 commit comments

Comments
 (0)