Spaces:
Running
Running
Commit
·
1922dbd
1
Parent(s):
1f96735
fix: linting and types for phase 5
Browse files- examples/orchestrator_demo/run_magentic.py +91 -0
- pyproject.toml +7 -1
- src/agents/__init__.py +0 -0
- src/agents/judge_agent.py +96 -0
- src/agents/search_agent.py +99 -0
- src/app.py +25 -4
- src/orchestrator_factory.py +52 -0
- src/orchestrator_magentic.py +185 -0
- src/utils/models.py +1 -0
- uv.lock +191 -1
examples/orchestrator_demo/run_magentic.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Demo: Magentic-One Orchestrator for DeepCritical.
|
| 4 |
+
|
| 5 |
+
This script demonstrates Phase 5 functionality:
|
| 6 |
+
- Multi-Agent Coordination (Searcher + Judge + Manager)
|
| 7 |
+
- Magentic-One Workflow
|
| 8 |
+
|
| 9 |
+
Usage:
|
| 10 |
+
export OPENAI_API_KEY=...
|
| 11 |
+
uv run python examples/orchestrator_demo/run_magentic.py "metformin cancer"
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
import argparse
|
| 15 |
+
import asyncio
|
| 16 |
+
import os
|
| 17 |
+
import sys
|
| 18 |
+
|
| 19 |
+
from src.agent_factory.judges import JudgeHandler
|
| 20 |
+
from src.orchestrator_factory import create_orchestrator
|
| 21 |
+
from src.tools.pubmed import PubMedTool
|
| 22 |
+
from src.tools.search_handler import SearchHandler
|
| 23 |
+
from src.tools.websearch import WebTool
|
| 24 |
+
from src.utils.models import OrchestratorConfig
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
async def main() -> None:
|
| 28 |
+
"""Run the magentic agent demo."""
|
| 29 |
+
parser = argparse.ArgumentParser(description="Run DeepCritical Magentic Agent")
|
| 30 |
+
parser.add_argument("query", help="Research query (e.g., 'metformin cancer')")
|
| 31 |
+
parser.add_argument("--iterations", type=int, default=10, help="Max rounds")
|
| 32 |
+
args = parser.parse_args()
|
| 33 |
+
|
| 34 |
+
# Check for keys
|
| 35 |
+
if not (os.getenv("OPENAI_API_KEY") or os.getenv("ANTHROPIC_API_KEY")):
|
| 36 |
+
print("Error: No API key found. Magentic requires real LLM.")
|
| 37 |
+
sys.exit(1)
|
| 38 |
+
|
| 39 |
+
print(f"\n{'='*60}")
|
| 40 |
+
print("DeepCritical Magentic Agent Demo")
|
| 41 |
+
print(f"Query: {args.query}")
|
| 42 |
+
print("Mode: MAGENTIC (Multi-Agent)")
|
| 43 |
+
print(f"{ '='*60}\n")
|
| 44 |
+
|
| 45 |
+
# 1. Setup Search Tools
|
| 46 |
+
search_handler = SearchHandler(tools=[PubMedTool(), WebTool()], timeout=30.0)
|
| 47 |
+
|
| 48 |
+
# 2. Setup Judge
|
| 49 |
+
judge_handler = JudgeHandler()
|
| 50 |
+
|
| 51 |
+
# 3. Setup Orchestrator via Factory
|
| 52 |
+
config = OrchestratorConfig(max_iterations=args.iterations)
|
| 53 |
+
orchestrator = create_orchestrator(
|
| 54 |
+
search_handler=search_handler,
|
| 55 |
+
judge_handler=judge_handler,
|
| 56 |
+
config=config,
|
| 57 |
+
mode="magentic",
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
if not orchestrator:
|
| 61 |
+
print("Failed to create Magentic orchestrator. Is agent-framework installed?")
|
| 62 |
+
sys.exit(1)
|
| 63 |
+
|
| 64 |
+
# 4. Run Loop
|
| 65 |
+
try:
|
| 66 |
+
async for event in orchestrator.run(args.query):
|
| 67 |
+
# Print event with icon
|
| 68 |
+
# Clean up markdown for CLI
|
| 69 |
+
msg_obj = event.message
|
| 70 |
+
msg_text = ""
|
| 71 |
+
if hasattr(msg_obj, "text"):
|
| 72 |
+
msg_text = msg_obj.text
|
| 73 |
+
else:
|
| 74 |
+
msg_text = str(msg_obj)
|
| 75 |
+
|
| 76 |
+
msg = msg_text.replace("\n", " ").replace("**", "")[:150]
|
| 77 |
+
print(f"[{event.type.upper()}] {msg}...")
|
| 78 |
+
|
| 79 |
+
if event.type == "complete":
|
| 80 |
+
print("\n--- FINAL OUTPUT ---\n")
|
| 81 |
+
print(msg_text)
|
| 82 |
+
|
| 83 |
+
except Exception as e:
|
| 84 |
+
print(f"\n❌ Error: {e}")
|
| 85 |
+
import traceback
|
| 86 |
+
|
| 87 |
+
traceback.print_exc()
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
if __name__ == "__main__":
|
| 91 |
+
asyncio.run(main())
|
pyproject.toml
CHANGED
|
@@ -46,6 +46,9 @@ dev = [
|
|
| 46 |
"mypy>=1.10",
|
| 47 |
"pre-commit>=3.7",
|
| 48 |
]
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
[build-system]
|
| 51 |
requires = ["hatchling"]
|
|
@@ -112,4 +115,7 @@ exclude_lines = [
|
|
| 112 |
"pragma: no cover",
|
| 113 |
"if TYPE_CHECKING:",
|
| 114 |
"raise NotImplementedError",
|
| 115 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
"mypy>=1.10",
|
| 47 |
"pre-commit>=3.7",
|
| 48 |
]
|
| 49 |
+
magentic = [
|
| 50 |
+
"agent-framework-core",
|
| 51 |
+
]
|
| 52 |
|
| 53 |
[build-system]
|
| 54 |
requires = ["hatchling"]
|
|
|
|
| 115 |
"pragma: no cover",
|
| 116 |
"if TYPE_CHECKING:",
|
| 117 |
"raise NotImplementedError",
|
| 118 |
+
]
|
| 119 |
+
|
| 120 |
+
[tool.uv.sources]
|
| 121 |
+
agent-framework-core = { path = "reference_repos/agent-framework/python/packages/core", editable = true }
|
src/agents/__init__.py
ADDED
|
File without changes
|
src/agents/judge_agent.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Judge agent wrapper for Magentic integration."""
|
| 2 |
+
|
| 3 |
+
from collections.abc import AsyncIterable
|
| 4 |
+
from typing import Any
|
| 5 |
+
|
| 6 |
+
from agent_framework import (
|
| 7 |
+
AgentRunResponse,
|
| 8 |
+
AgentRunResponseUpdate,
|
| 9 |
+
AgentThread,
|
| 10 |
+
BaseAgent,
|
| 11 |
+
ChatMessage,
|
| 12 |
+
Role,
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
from src.orchestrator import JudgeHandlerProtocol
|
| 16 |
+
from src.utils.models import Evidence, JudgeAssessment
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class JudgeAgent(BaseAgent): # type: ignore[misc]
|
| 20 |
+
"""Wraps JudgeHandler as an AgentProtocol for Magentic."""
|
| 21 |
+
|
| 22 |
+
def __init__(
|
| 23 |
+
self,
|
| 24 |
+
judge_handler: JudgeHandlerProtocol,
|
| 25 |
+
evidence_store: dict[str, list[Evidence]],
|
| 26 |
+
) -> None:
|
| 27 |
+
super().__init__(
|
| 28 |
+
name="JudgeAgent",
|
| 29 |
+
description="Evaluates evidence quality and determines if sufficient for synthesis",
|
| 30 |
+
)
|
| 31 |
+
self._handler = judge_handler
|
| 32 |
+
self._evidence_store = evidence_store # Shared state for evidence
|
| 33 |
+
|
| 34 |
+
async def run(
|
| 35 |
+
self,
|
| 36 |
+
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
|
| 37 |
+
*,
|
| 38 |
+
thread: AgentThread | None = None,
|
| 39 |
+
**kwargs: Any,
|
| 40 |
+
) -> AgentRunResponse:
|
| 41 |
+
"""Assess evidence quality."""
|
| 42 |
+
# Extract original question from messages
|
| 43 |
+
question = ""
|
| 44 |
+
if isinstance(messages, list):
|
| 45 |
+
for msg in reversed(messages):
|
| 46 |
+
if isinstance(msg, ChatMessage) and msg.role == Role.USER and msg.text:
|
| 47 |
+
question = msg.text
|
| 48 |
+
break
|
| 49 |
+
elif isinstance(msg, str):
|
| 50 |
+
question = msg
|
| 51 |
+
break
|
| 52 |
+
elif isinstance(messages, str):
|
| 53 |
+
question = messages
|
| 54 |
+
|
| 55 |
+
# Get evidence from shared store
|
| 56 |
+
evidence = self._evidence_store.get("current", [])
|
| 57 |
+
|
| 58 |
+
# Assess
|
| 59 |
+
assessment: JudgeAssessment = await self._handler.assess(question, evidence)
|
| 60 |
+
|
| 61 |
+
# Format response
|
| 62 |
+
response_text = f"""## Assessment
|
| 63 |
+
|
| 64 |
+
**Sufficient**: {assessment.sufficient}
|
| 65 |
+
**Confidence**: {assessment.confidence:.0%}
|
| 66 |
+
**Recommendation**: {assessment.recommendation}
|
| 67 |
+
|
| 68 |
+
### Scores
|
| 69 |
+
- Mechanism: {assessment.details.mechanism_score}/10
|
| 70 |
+
- Clinical: {assessment.details.clinical_evidence_score}/10
|
| 71 |
+
|
| 72 |
+
### Reasoning
|
| 73 |
+
{assessment.reasoning}
|
| 74 |
+
"""
|
| 75 |
+
|
| 76 |
+
if assessment.next_search_queries:
|
| 77 |
+
response_text += "\n### Next Queries\n" + "\n".join(
|
| 78 |
+
f"- {q}" for q in assessment.next_search_queries
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
return AgentRunResponse(
|
| 82 |
+
messages=[ChatMessage(role=Role.ASSISTANT, text=response_text)],
|
| 83 |
+
response_id=f"judge-{assessment.recommendation}",
|
| 84 |
+
additional_properties={"assessment": assessment.model_dump()},
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
async def run_stream(
|
| 88 |
+
self,
|
| 89 |
+
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
|
| 90 |
+
*,
|
| 91 |
+
thread: AgentThread | None = None,
|
| 92 |
+
**kwargs: Any,
|
| 93 |
+
) -> AsyncIterable[AgentRunResponseUpdate]:
|
| 94 |
+
"""Streaming wrapper for judge."""
|
| 95 |
+
result = await self.run(messages, thread=thread, **kwargs)
|
| 96 |
+
yield AgentRunResponseUpdate(messages=result.messages, response_id=result.response_id)
|
src/agents/search_agent.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections.abc import AsyncIterable
|
| 2 |
+
from typing import Any
|
| 3 |
+
|
| 4 |
+
from agent_framework import (
|
| 5 |
+
AgentRunResponse,
|
| 6 |
+
AgentRunResponseUpdate,
|
| 7 |
+
AgentThread,
|
| 8 |
+
BaseAgent,
|
| 9 |
+
ChatMessage,
|
| 10 |
+
Role,
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
from src.orchestrator import SearchHandlerProtocol
|
| 14 |
+
from src.utils.models import Evidence, SearchResult
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class SearchAgent(BaseAgent): # type: ignore[misc]
|
| 18 |
+
"""Wraps SearchHandler as an AgentProtocol for Magentic."""
|
| 19 |
+
|
| 20 |
+
def __init__(
|
| 21 |
+
self,
|
| 22 |
+
search_handler: SearchHandlerProtocol,
|
| 23 |
+
evidence_store: dict[str, list[Evidence]],
|
| 24 |
+
) -> None:
|
| 25 |
+
super().__init__(
|
| 26 |
+
name="SearchAgent",
|
| 27 |
+
description="Searches PubMed and web for drug repurposing evidence",
|
| 28 |
+
)
|
| 29 |
+
self._handler = search_handler
|
| 30 |
+
self._evidence_store = evidence_store
|
| 31 |
+
|
| 32 |
+
async def run(
|
| 33 |
+
self,
|
| 34 |
+
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
|
| 35 |
+
*,
|
| 36 |
+
thread: AgentThread | None = None,
|
| 37 |
+
**kwargs: Any,
|
| 38 |
+
) -> AgentRunResponse:
|
| 39 |
+
"""Execute search based on the last user message."""
|
| 40 |
+
# Extract query from messages
|
| 41 |
+
query = ""
|
| 42 |
+
if isinstance(messages, list):
|
| 43 |
+
for msg in reversed(messages):
|
| 44 |
+
if isinstance(msg, ChatMessage) and msg.role == Role.USER and msg.text:
|
| 45 |
+
query = msg.text
|
| 46 |
+
break
|
| 47 |
+
elif isinstance(msg, str):
|
| 48 |
+
query = msg
|
| 49 |
+
break
|
| 50 |
+
elif isinstance(messages, str):
|
| 51 |
+
query = messages
|
| 52 |
+
|
| 53 |
+
if not query:
|
| 54 |
+
return AgentRunResponse(
|
| 55 |
+
messages=[ChatMessage(role=Role.ASSISTANT, text="No query provided")],
|
| 56 |
+
response_id="search-no-query",
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
# Execute search
|
| 60 |
+
result: SearchResult = await self._handler.execute(query, max_results_per_tool=10)
|
| 61 |
+
|
| 62 |
+
# Update shared evidence store
|
| 63 |
+
# We append new evidence, deduplicating by URL is handled in Orchestrator usually,
|
| 64 |
+
# but here we should probably add to the list.
|
| 65 |
+
# For simplicity in this MVP phase, we just extend the list.
|
| 66 |
+
# Ideally, we should dedupe.
|
| 67 |
+
existing_urls = {e.citation.url for e in self._evidence_store["current"]}
|
| 68 |
+
new_unique = [e for e in result.evidence if e.citation.url not in existing_urls]
|
| 69 |
+
self._evidence_store["current"].extend(new_unique)
|
| 70 |
+
|
| 71 |
+
# Format response
|
| 72 |
+
evidence_text = "\n".join(
|
| 73 |
+
[
|
| 74 |
+
f"- [{e.citation.title}]({e.citation.url}): {e.content[:200]}..."
|
| 75 |
+
for e in result.evidence[:5]
|
| 76 |
+
]
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
response_text = (
|
| 80 |
+
f"Found {result.total_found} sources ({len(new_unique)} new):\n\n{evidence_text}"
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
return AgentRunResponse(
|
| 84 |
+
messages=[ChatMessage(role=Role.ASSISTANT, text=response_text)],
|
| 85 |
+
response_id=f"search-{result.total_found}",
|
| 86 |
+
additional_properties={"evidence": [e.model_dump() for e in result.evidence]},
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
async def run_stream(
|
| 90 |
+
self,
|
| 91 |
+
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
|
| 92 |
+
*,
|
| 93 |
+
thread: AgentThread | None = None,
|
| 94 |
+
**kwargs: Any,
|
| 95 |
+
) -> AsyncIterable[AgentRunResponseUpdate]:
|
| 96 |
+
"""Streaming wrapper for search (search itself isn't streaming)."""
|
| 97 |
+
result = await self.run(messages, thread=thread, **kwargs)
|
| 98 |
+
# Yield single update with full result
|
| 99 |
+
yield AgentRunResponseUpdate(messages=result.messages, response_id=result.response_id)
|
src/app.py
CHANGED
|
@@ -7,19 +7,20 @@ from typing import Any
|
|
| 7 |
import gradio as gr
|
| 8 |
|
| 9 |
from src.agent_factory.judges import JudgeHandler, MockJudgeHandler
|
| 10 |
-
from src.
|
| 11 |
from src.tools.pubmed import PubMedTool
|
| 12 |
from src.tools.search_handler import SearchHandler
|
| 13 |
from src.tools.websearch import WebTool
|
| 14 |
from src.utils.models import OrchestratorConfig
|
| 15 |
|
| 16 |
|
| 17 |
-
def
|
| 18 |
"""
|
| 19 |
Create an orchestrator instance.
|
| 20 |
|
| 21 |
Args:
|
| 22 |
use_mock: If True, use MockJudgeHandler (no API key needed)
|
|
|
|
| 23 |
|
| 24 |
Returns:
|
| 25 |
Configured Orchestrator instance
|
|
@@ -43,16 +44,18 @@ def create_orchestrator(use_mock: bool = False) -> Orchestrator:
|
|
| 43 |
else:
|
| 44 |
judge_handler = JudgeHandler()
|
| 45 |
|
| 46 |
-
return
|
| 47 |
search_handler=search_handler,
|
| 48 |
judge_handler=judge_handler,
|
| 49 |
config=config,
|
|
|
|
| 50 |
)
|
| 51 |
|
| 52 |
|
| 53 |
async def research_agent(
|
| 54 |
message: str,
|
| 55 |
history: list[dict[str, Any]],
|
|
|
|
| 56 |
) -> AsyncGenerator[str, None]:
|
| 57 |
"""
|
| 58 |
Gradio chat function that runs the research agent.
|
|
@@ -60,6 +63,7 @@ async def research_agent(
|
|
| 60 |
Args:
|
| 61 |
message: User's research question
|
| 62 |
history: Chat history (Gradio format)
|
|
|
|
| 63 |
|
| 64 |
Yields:
|
| 65 |
Markdown-formatted responses for streaming
|
|
@@ -70,7 +74,16 @@ async def research_agent(
|
|
| 70 |
|
| 71 |
# Create orchestrator (use mock if no API key)
|
| 72 |
use_mock = not (os.getenv("OPENAI_API_KEY") or os.getenv("ANTHROPIC_API_KEY"))
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
# Run the agent and stream events
|
| 76 |
response_parts = []
|
|
@@ -126,6 +139,14 @@ def create_demo() -> Any:
|
|
| 126 |
"What medications show promise for Long COVID treatment?",
|
| 127 |
"Can statins be repurposed for neurological conditions?",
|
| 128 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
)
|
| 130 |
|
| 131 |
gr.Markdown("""
|
|
|
|
| 7 |
import gradio as gr
|
| 8 |
|
| 9 |
from src.agent_factory.judges import JudgeHandler, MockJudgeHandler
|
| 10 |
+
from src.orchestrator_factory import create_orchestrator
|
| 11 |
from src.tools.pubmed import PubMedTool
|
| 12 |
from src.tools.search_handler import SearchHandler
|
| 13 |
from src.tools.websearch import WebTool
|
| 14 |
from src.utils.models import OrchestratorConfig
|
| 15 |
|
| 16 |
|
| 17 |
+
def configure_orchestrator(use_mock: bool = False, mode: str = "simple") -> Any:
|
| 18 |
"""
|
| 19 |
Create an orchestrator instance.
|
| 20 |
|
| 21 |
Args:
|
| 22 |
use_mock: If True, use MockJudgeHandler (no API key needed)
|
| 23 |
+
mode: Orchestrator mode ("simple" or "magentic")
|
| 24 |
|
| 25 |
Returns:
|
| 26 |
Configured Orchestrator instance
|
|
|
|
| 44 |
else:
|
| 45 |
judge_handler = JudgeHandler()
|
| 46 |
|
| 47 |
+
return create_orchestrator(
|
| 48 |
search_handler=search_handler,
|
| 49 |
judge_handler=judge_handler,
|
| 50 |
config=config,
|
| 51 |
+
mode=mode, # type: ignore
|
| 52 |
)
|
| 53 |
|
| 54 |
|
| 55 |
async def research_agent(
|
| 56 |
message: str,
|
| 57 |
history: list[dict[str, Any]],
|
| 58 |
+
mode: str = "simple",
|
| 59 |
) -> AsyncGenerator[str, None]:
|
| 60 |
"""
|
| 61 |
Gradio chat function that runs the research agent.
|
|
|
|
| 63 |
Args:
|
| 64 |
message: User's research question
|
| 65 |
history: Chat history (Gradio format)
|
| 66 |
+
mode: Orchestrator mode ("simple" or "magentic")
|
| 67 |
|
| 68 |
Yields:
|
| 69 |
Markdown-formatted responses for streaming
|
|
|
|
| 74 |
|
| 75 |
# Create orchestrator (use mock if no API key)
|
| 76 |
use_mock = not (os.getenv("OPENAI_API_KEY") or os.getenv("ANTHROPIC_API_KEY"))
|
| 77 |
+
|
| 78 |
+
# If magentic mode requested but no keys, fallback/warn
|
| 79 |
+
if mode == "magentic" and use_mock:
|
| 80 |
+
yield (
|
| 81 |
+
"⚠️ **Warning**: Magentic mode requires valid API keys. "
|
| 82 |
+
"Falling back to Mock Simple mode."
|
| 83 |
+
)
|
| 84 |
+
mode = "simple"
|
| 85 |
+
|
| 86 |
+
orchestrator = configure_orchestrator(use_mock=use_mock, mode=mode)
|
| 87 |
|
| 88 |
# Run the agent and stream events
|
| 89 |
response_parts = []
|
|
|
|
| 139 |
"What medications show promise for Long COVID treatment?",
|
| 140 |
"Can statins be repurposed for neurological conditions?",
|
| 141 |
],
|
| 142 |
+
additional_inputs=[
|
| 143 |
+
gr.Radio(
|
| 144 |
+
choices=["simple", "magentic"],
|
| 145 |
+
value="simple",
|
| 146 |
+
label="Orchestrator Mode",
|
| 147 |
+
info="Simple: Linear loop | Magentic: Multi-Agent (Requires OpenAI Key)",
|
| 148 |
+
)
|
| 149 |
+
],
|
| 150 |
)
|
| 151 |
|
| 152 |
gr.Markdown("""
|
src/orchestrator_factory.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Factory for creating orchestrators."""
|
| 2 |
+
|
| 3 |
+
from typing import Any, Literal
|
| 4 |
+
|
| 5 |
+
from src.orchestrator import JudgeHandlerProtocol, Orchestrator, SearchHandlerProtocol
|
| 6 |
+
from src.utils.models import OrchestratorConfig
|
| 7 |
+
|
| 8 |
+
# Define protocols again or import if they were in a shared place.
|
| 9 |
+
|
| 10 |
+
# Since they are in src/orchestrator.py, we can import them?
|
| 11 |
+
|
| 12 |
+
# But SearchHandler and JudgeHandler in arguments are concrete classes in the type hint,
|
| 13 |
+
|
| 14 |
+
# which satisfy the protocol.
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def create_orchestrator(
|
| 18 |
+
search_handler: SearchHandlerProtocol,
|
| 19 |
+
judge_handler: JudgeHandlerProtocol,
|
| 20 |
+
config: OrchestratorConfig | None = None,
|
| 21 |
+
mode: Literal["simple", "magentic"] = "simple",
|
| 22 |
+
) -> Any:
|
| 23 |
+
"""
|
| 24 |
+
Create an orchestrator instance.
|
| 25 |
+
|
| 26 |
+
Args:
|
| 27 |
+
search_handler: The search handler
|
| 28 |
+
judge_handler: The judge handler
|
| 29 |
+
config: Optional configuration
|
| 30 |
+
mode: "simple" for Phase 4 loop, "magentic" for Phase 5 multi-agent
|
| 31 |
+
|
| 32 |
+
Returns:
|
| 33 |
+
Orchestrator instance (same interface regardless of mode)
|
| 34 |
+
"""
|
| 35 |
+
if mode == "magentic":
|
| 36 |
+
try:
|
| 37 |
+
from src.orchestrator_magentic import MagenticOrchestrator
|
| 38 |
+
|
| 39 |
+
return MagenticOrchestrator(
|
| 40 |
+
search_handler=search_handler,
|
| 41 |
+
judge_handler=judge_handler,
|
| 42 |
+
max_rounds=config.max_iterations if config else 10,
|
| 43 |
+
)
|
| 44 |
+
except ImportError:
|
| 45 |
+
# Fallback to simple if agent-framework not installed
|
| 46 |
+
pass
|
| 47 |
+
|
| 48 |
+
return Orchestrator(
|
| 49 |
+
search_handler=search_handler,
|
| 50 |
+
judge_handler=judge_handler,
|
| 51 |
+
config=config,
|
| 52 |
+
)
|
src/orchestrator_magentic.py
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Magentic-based orchestrator for DeepCritical."""
|
| 2 |
+
|
| 3 |
+
from collections.abc import AsyncGenerator
|
| 4 |
+
|
| 5 |
+
import structlog
|
| 6 |
+
from agent_framework import (
|
| 7 |
+
MagenticAgentDeltaEvent,
|
| 8 |
+
MagenticAgentMessageEvent,
|
| 9 |
+
MagenticBuilder,
|
| 10 |
+
MagenticFinalResultEvent,
|
| 11 |
+
MagenticOrchestratorMessageEvent,
|
| 12 |
+
WorkflowOutputEvent,
|
| 13 |
+
)
|
| 14 |
+
from agent_framework.openai import OpenAIChatClient
|
| 15 |
+
|
| 16 |
+
from src.agents.judge_agent import JudgeAgent
|
| 17 |
+
from src.agents.search_agent import SearchAgent
|
| 18 |
+
from src.orchestrator import JudgeHandlerProtocol, SearchHandlerProtocol
|
| 19 |
+
from src.utils.config import settings
|
| 20 |
+
from src.utils.models import AgentEvent, Evidence
|
| 21 |
+
|
| 22 |
+
logger = structlog.get_logger()
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class MagenticOrchestrator:
|
| 26 |
+
"""
|
| 27 |
+
Magentic-based orchestrator - same API as Orchestrator.
|
| 28 |
+
|
| 29 |
+
Uses Microsoft Agent Framework's MagenticBuilder for multi-agent coordination.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
def __init__(
|
| 33 |
+
self,
|
| 34 |
+
search_handler: SearchHandlerProtocol,
|
| 35 |
+
judge_handler: JudgeHandlerProtocol,
|
| 36 |
+
max_rounds: int = 10,
|
| 37 |
+
) -> None:
|
| 38 |
+
self._search_handler = search_handler
|
| 39 |
+
self._judge_handler = judge_handler
|
| 40 |
+
self._max_rounds = max_rounds
|
| 41 |
+
self._evidence_store: dict[str, list[Evidence]] = {"current": []}
|
| 42 |
+
|
| 43 |
+
async def run(self, query: str) -> AsyncGenerator[AgentEvent, None]: # noqa: PLR0912
|
| 44 |
+
"""
|
| 45 |
+
Run the Magentic workflow - same API as simple Orchestrator.
|
| 46 |
+
|
| 47 |
+
Yields AgentEvent objects for real-time UI updates.
|
| 48 |
+
"""
|
| 49 |
+
logger.info("Starting Magentic orchestrator", query=query)
|
| 50 |
+
|
| 51 |
+
yield AgentEvent(
|
| 52 |
+
type="started",
|
| 53 |
+
message=f"Starting research (Magentic mode): {query}",
|
| 54 |
+
iteration=0,
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
# Create agent wrappers
|
| 58 |
+
search_agent = SearchAgent(self._search_handler, self._evidence_store)
|
| 59 |
+
judge_agent = JudgeAgent(self._judge_handler, self._evidence_store)
|
| 60 |
+
|
| 61 |
+
# Build Magentic workflow
|
| 62 |
+
# Note: MagenticBuilder.participants takes named arguments for agent instances
|
| 63 |
+
workflow = (
|
| 64 |
+
MagenticBuilder()
|
| 65 |
+
.participants(
|
| 66 |
+
searcher=search_agent,
|
| 67 |
+
judge=judge_agent,
|
| 68 |
+
)
|
| 69 |
+
.with_standard_manager(
|
| 70 |
+
chat_client=OpenAIChatClient(
|
| 71 |
+
model_id=settings.openai_model, api_key=settings.openai_api_key
|
| 72 |
+
),
|
| 73 |
+
max_round_count=self._max_rounds,
|
| 74 |
+
max_stall_count=3,
|
| 75 |
+
max_reset_count=2,
|
| 76 |
+
)
|
| 77 |
+
.build()
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
# Task instruction for the manager
|
| 81 |
+
task = f"""Research drug repurposing opportunities for: {query}
|
| 82 |
+
|
| 83 |
+
Instructions:
|
| 84 |
+
1. Use SearcherAgent to find evidence. SEND ONLY A SIMPLE KEYWORD QUERY (e.g. "metformin aging")
|
| 85 |
+
as the instruction. Complex queries fail.
|
| 86 |
+
2. Use JudgeAgent to evaluate if evidence is sufficient.
|
| 87 |
+
3. If JudgeAgent says "continue", search with refined queries.
|
| 88 |
+
4. If JudgeAgent says "synthesize", provide final synthesis
|
| 89 |
+
5. Stop when synthesis is ready or max rounds reached
|
| 90 |
+
|
| 91 |
+
Focus on finding:
|
| 92 |
+
- Mechanism of action evidence
|
| 93 |
+
- Clinical/preclinical studies
|
| 94 |
+
- Specific drug candidates
|
| 95 |
+
"""
|
| 96 |
+
|
| 97 |
+
iteration = 0
|
| 98 |
+
try:
|
| 99 |
+
# workflow.run_stream returns an async generator of workflow events
|
| 100 |
+
# We use 'await' in the for loop for async generator
|
| 101 |
+
async for event in workflow.run_stream(task):
|
| 102 |
+
if isinstance(event, MagenticOrchestratorMessageEvent):
|
| 103 |
+
# Manager events (planning, instruction, ledger)
|
| 104 |
+
# The 'message' attribute might be None if it's just a state change,
|
| 105 |
+
# check message presence
|
| 106 |
+
message_text = (
|
| 107 |
+
event.message.text
|
| 108 |
+
if event.message and hasattr(event.message, "text")
|
| 109 |
+
else ""
|
| 110 |
+
)
|
| 111 |
+
# kind might be 'plan', 'instruction', etc.
|
| 112 |
+
kind = getattr(event, "kind", "manager")
|
| 113 |
+
|
| 114 |
+
if message_text:
|
| 115 |
+
yield AgentEvent(
|
| 116 |
+
type="judging",
|
| 117 |
+
message=f"Manager ({kind}): {message_text[:100]}...",
|
| 118 |
+
iteration=iteration,
|
| 119 |
+
)
|
| 120 |
+
|
| 121 |
+
elif isinstance(event, MagenticAgentMessageEvent):
|
| 122 |
+
# Complete agent response
|
| 123 |
+
iteration += 1
|
| 124 |
+
agent_name = event.agent_id or "unknown"
|
| 125 |
+
msg_text = (
|
| 126 |
+
event.message.text
|
| 127 |
+
if event.message and hasattr(event.message, "text")
|
| 128 |
+
else ""
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
if "search" in agent_name.lower():
|
| 132 |
+
# Check if we found evidence (based on SearchAgent logic)
|
| 133 |
+
yield AgentEvent(
|
| 134 |
+
type="search_complete",
|
| 135 |
+
message=f"Search agent: {msg_text[:100]}...",
|
| 136 |
+
iteration=iteration,
|
| 137 |
+
)
|
| 138 |
+
elif "judge" in agent_name.lower():
|
| 139 |
+
yield AgentEvent(
|
| 140 |
+
type="judge_complete",
|
| 141 |
+
message=f"Judge agent: {msg_text[:100]}...",
|
| 142 |
+
iteration=iteration,
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
elif isinstance(event, MagenticFinalResultEvent):
|
| 146 |
+
# Final workflow result
|
| 147 |
+
final_text = (
|
| 148 |
+
event.message.text
|
| 149 |
+
if event.message and hasattr(event.message, "text")
|
| 150 |
+
else "No result"
|
| 151 |
+
)
|
| 152 |
+
yield AgentEvent(
|
| 153 |
+
type="complete",
|
| 154 |
+
message=final_text,
|
| 155 |
+
data={"iterations": iteration},
|
| 156 |
+
iteration=iteration,
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
+
elif isinstance(event, MagenticAgentDeltaEvent):
|
| 160 |
+
# Streaming token chunks from agents (optional "typing" effect)
|
| 161 |
+
# Only emit if we have actual text content
|
| 162 |
+
if event.text:
|
| 163 |
+
yield AgentEvent(
|
| 164 |
+
type="streaming",
|
| 165 |
+
message=event.text,
|
| 166 |
+
data={"agent_id": event.agent_id},
|
| 167 |
+
iteration=iteration,
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
+
elif isinstance(event, WorkflowOutputEvent):
|
| 171 |
+
# Alternative final output event
|
| 172 |
+
if event.data:
|
| 173 |
+
yield AgentEvent(
|
| 174 |
+
type="complete",
|
| 175 |
+
message=str(event.data),
|
| 176 |
+
iteration=iteration,
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
except Exception as e:
|
| 180 |
+
logger.error("Magentic workflow failed", error=str(e))
|
| 181 |
+
yield AgentEvent(
|
| 182 |
+
type="error",
|
| 183 |
+
message=f"Workflow error: {e!s}",
|
| 184 |
+
iteration=iteration,
|
| 185 |
+
)
|
src/utils/models.py
CHANGED
|
@@ -106,6 +106,7 @@ class AgentEvent(BaseModel):
|
|
| 106 |
"synthesizing",
|
| 107 |
"complete",
|
| 108 |
"error",
|
|
|
|
| 109 |
]
|
| 110 |
message: str
|
| 111 |
data: Any = None
|
|
|
|
| 106 |
"synthesizing",
|
| 107 |
"complete",
|
| 108 |
"error",
|
| 109 |
+
"streaming",
|
| 110 |
]
|
| 111 |
message: str
|
| 112 |
data: Any = None
|
uv.lock
CHANGED
|
@@ -19,6 +19,54 @@ wheels = [
|
|
| 19 |
{ url = "https://files.pythonhosted.org/packages/8f/78/eb55fabaab41abc53f52c0918a9a8c0f747807e5306273f51120fd695957/ag_ui_protocol-0.1.10-py3-none-any.whl", hash = "sha256:c81e6981f30aabdf97a7ee312bfd4df0cd38e718d9fc10019c7d438128b93ab5", size = 7889 },
|
| 20 |
]
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
[[package]]
|
| 23 |
name = "aiofiles"
|
| 24 |
version = "24.1.0"
|
|
@@ -165,6 +213,35 @@ wheels = [
|
|
| 165 |
{ url = "https://files.pythonhosted.org/packages/f8/aa/5082412d1ee302e9e7d80b6949bc4d2a8fa1149aaab610c5fc24709605d6/authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a", size = 243608 },
|
| 166 |
]
|
| 167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
[[package]]
|
| 169 |
name = "backports-tarfile"
|
| 170 |
version = "1.2.0"
|
|
@@ -684,9 +761,13 @@ dev = [
|
|
| 684 |
{ name = "respx" },
|
| 685 |
{ name = "ruff" },
|
| 686 |
]
|
|
|
|
|
|
|
|
|
|
| 687 |
|
| 688 |
[package.metadata]
|
| 689 |
requires-dist = [
|
|
|
|
| 690 |
{ name = "anthropic", specifier = ">=0.18.0" },
|
| 691 |
{ name = "beautifulsoup4", specifier = ">=4.12" },
|
| 692 |
{ name = "duckduckgo-search", specifier = ">=6.0" },
|
|
@@ -710,7 +791,7 @@ requires-dist = [
|
|
| 710 |
{ name = "tenacity", specifier = ">=8.2" },
|
| 711 |
{ name = "xmltodict", specifier = ">=0.13" },
|
| 712 |
]
|
| 713 |
-
provides-extras = ["dev"]
|
| 714 |
|
| 715 |
[[package]]
|
| 716 |
name = "diskcache"
|
|
@@ -1083,6 +1164,57 @@ wheels = [
|
|
| 1083 |
{ url = "https://files.pythonhosted.org/packages/27/79/28f295d5064750674014f50e3c2daf8dc233964c904d357ac2bd0e33fc31/groq-0.36.0-py3-none-any.whl", hash = "sha256:ac7eeae31a5c2e76d30ea678f0b1a9168ff906c4440f5ec3a42ac74d5b4fdb3c", size = 137279 },
|
| 1084 |
]
|
| 1085 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1086 |
[[package]]
|
| 1087 |
name = "h11"
|
| 1088 |
version = "0.16.0"
|
|
@@ -1683,6 +1815,11 @@ wheels = [
|
|
| 1683 |
{ url = "https://files.pythonhosted.org/packages/a9/bb/711099f9c6bb52770f56e56401cdfb10da5b67029f701e0df29362df4c8e/mcp-1.22.0-py3-none-any.whl", hash = "sha256:bed758e24df1ed6846989c909ba4e3df339a27b4f30f1b8b627862a4bade4e98", size = 175489 },
|
| 1684 |
]
|
| 1685 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1686 |
[[package]]
|
| 1687 |
name = "mdurl"
|
| 1688 |
version = "0.1.2"
|
|
@@ -1719,6 +1856,32 @@ wheels = [
|
|
| 1719 |
{ url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 },
|
| 1720 |
]
|
| 1721 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1722 |
[[package]]
|
| 1723 |
name = "mypy"
|
| 1724 |
version = "1.18.2"
|
|
@@ -1924,6 +2087,24 @@ wheels = [
|
|
| 1924 |
{ url = "https://files.pythonhosted.org/packages/a7/9e/55a41c9601191e8cd8eb626b54ee6827b9c9d4a46d736f32abc80d8039fc/opentelemetry_exporter_otlp_proto_common-1.38.0-py3-none-any.whl", hash = "sha256:03cb76ab213300fe4f4c62b7d8f17d97fcfd21b89f0b5ce38ea156327ddda74a", size = 18359 },
|
| 1925 |
]
|
| 1926 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1927 |
[[package]]
|
| 1928 |
name = "opentelemetry-exporter-otlp-proto-http"
|
| 1929 |
version = "1.38.0"
|
|
@@ -2012,6 +2193,15 @@ wheels = [
|
|
| 2012 |
{ url = "https://files.pythonhosted.org/packages/24/7d/c88d7b15ba8fe5c6b8f93be50fc11795e9fc05386c44afaf6b76fe191f9b/opentelemetry_semantic_conventions-0.59b0-py3-none-any.whl", hash = "sha256:35d3b8833ef97d614136e253c1da9342b4c3c083bbaf29ce31d572a1c3825eed", size = 207954 },
|
| 2013 |
]
|
| 2014 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2015 |
[[package]]
|
| 2016 |
name = "opentelemetry-util-http"
|
| 2017 |
version = "0.59b0"
|
|
|
|
| 19 |
{ url = "https://files.pythonhosted.org/packages/8f/78/eb55fabaab41abc53f52c0918a9a8c0f747807e5306273f51120fd695957/ag_ui_protocol-0.1.10-py3-none-any.whl", hash = "sha256:c81e6981f30aabdf97a7ee312bfd4df0cd38e718d9fc10019c7d438128b93ab5", size = 7889 },
|
| 20 |
]
|
| 21 |
|
| 22 |
+
[[package]]
|
| 23 |
+
name = "agent-framework-core"
|
| 24 |
+
version = "1.0.0b251120"
|
| 25 |
+
source = { editable = "reference_repos/agent-framework/python/packages/core" }
|
| 26 |
+
dependencies = [
|
| 27 |
+
{ name = "azure-identity" },
|
| 28 |
+
{ name = "mcp", extra = ["ws"] },
|
| 29 |
+
{ name = "openai" },
|
| 30 |
+
{ name = "opentelemetry-api" },
|
| 31 |
+
{ name = "opentelemetry-exporter-otlp-proto-grpc" },
|
| 32 |
+
{ name = "opentelemetry-sdk" },
|
| 33 |
+
{ name = "opentelemetry-semantic-conventions-ai" },
|
| 34 |
+
{ name = "packaging" },
|
| 35 |
+
{ name = "pydantic" },
|
| 36 |
+
{ name = "pydantic-settings" },
|
| 37 |
+
{ name = "typing-extensions" },
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
[package.metadata]
|
| 41 |
+
requires-dist = [
|
| 42 |
+
{ name = "agent-framework-a2a", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/a2a" },
|
| 43 |
+
{ name = "agent-framework-ag-ui", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/ag-ui" },
|
| 44 |
+
{ name = "agent-framework-anthropic", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/anthropic" },
|
| 45 |
+
{ name = "agent-framework-azure-ai", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/azure-ai" },
|
| 46 |
+
{ name = "agent-framework-azure-ai-search", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/azure-ai-search" },
|
| 47 |
+
{ name = "agent-framework-azurefunctions", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/azurefunctions" },
|
| 48 |
+
{ name = "agent-framework-chatkit", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/chatkit" },
|
| 49 |
+
{ name = "agent-framework-copilotstudio", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/copilotstudio" },
|
| 50 |
+
{ name = "agent-framework-declarative", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/declarative" },
|
| 51 |
+
{ name = "agent-framework-devui", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/devui" },
|
| 52 |
+
{ name = "agent-framework-lab", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/lab" },
|
| 53 |
+
{ name = "agent-framework-mem0", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/mem0" },
|
| 54 |
+
{ name = "agent-framework-purview", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/purview" },
|
| 55 |
+
{ name = "agent-framework-redis", marker = "extra == 'all'", editable = "reference_repos/agent-framework/python/packages/redis" },
|
| 56 |
+
{ name = "azure-identity", specifier = ">=1,<2" },
|
| 57 |
+
{ name = "mcp", extras = ["ws"], specifier = ">=1.13" },
|
| 58 |
+
{ name = "openai", specifier = ">=1.99.0" },
|
| 59 |
+
{ name = "opentelemetry-api", specifier = ">=1.24" },
|
| 60 |
+
{ name = "opentelemetry-exporter-otlp-proto-grpc", specifier = ">=1.36.0" },
|
| 61 |
+
{ name = "opentelemetry-sdk", specifier = ">=1.24" },
|
| 62 |
+
{ name = "opentelemetry-semantic-conventions-ai", specifier = ">=0.4.13" },
|
| 63 |
+
{ name = "packaging", specifier = ">=24.1" },
|
| 64 |
+
{ name = "pydantic", specifier = ">=2,<3" },
|
| 65 |
+
{ name = "pydantic-settings", specifier = ">=2,<3" },
|
| 66 |
+
{ name = "typing-extensions" },
|
| 67 |
+
]
|
| 68 |
+
provides-extras = ["all"]
|
| 69 |
+
|
| 70 |
[[package]]
|
| 71 |
name = "aiofiles"
|
| 72 |
version = "24.1.0"
|
|
|
|
| 213 |
{ url = "https://files.pythonhosted.org/packages/f8/aa/5082412d1ee302e9e7d80b6949bc4d2a8fa1149aaab610c5fc24709605d6/authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a", size = 243608 },
|
| 214 |
]
|
| 215 |
|
| 216 |
+
[[package]]
|
| 217 |
+
name = "azure-core"
|
| 218 |
+
version = "1.36.0"
|
| 219 |
+
source = { registry = "https://pypi.org/simple" }
|
| 220 |
+
dependencies = [
|
| 221 |
+
{ name = "requests" },
|
| 222 |
+
{ name = "typing-extensions" },
|
| 223 |
+
]
|
| 224 |
+
sdist = { url = "https://files.pythonhosted.org/packages/0a/c4/d4ff3bc3ddf155156460bff340bbe9533f99fac54ddea165f35a8619f162/azure_core-1.36.0.tar.gz", hash = "sha256:22e5605e6d0bf1d229726af56d9e92bc37b6e726b141a18be0b4d424131741b7", size = 351139 }
|
| 225 |
+
wheels = [
|
| 226 |
+
{ url = "https://files.pythonhosted.org/packages/b1/3c/b90d5afc2e47c4a45f4bba00f9c3193b0417fad5ad3bb07869f9d12832aa/azure_core-1.36.0-py3-none-any.whl", hash = "sha256:fee9923a3a753e94a259563429f3644aaf05c486d45b1215d098115102d91d3b", size = 213302 },
|
| 227 |
+
]
|
| 228 |
+
|
| 229 |
+
[[package]]
|
| 230 |
+
name = "azure-identity"
|
| 231 |
+
version = "1.25.1"
|
| 232 |
+
source = { registry = "https://pypi.org/simple" }
|
| 233 |
+
dependencies = [
|
| 234 |
+
{ name = "azure-core" },
|
| 235 |
+
{ name = "cryptography" },
|
| 236 |
+
{ name = "msal" },
|
| 237 |
+
{ name = "msal-extensions" },
|
| 238 |
+
{ name = "typing-extensions" },
|
| 239 |
+
]
|
| 240 |
+
sdist = { url = "https://files.pythonhosted.org/packages/06/8d/1a6c41c28a37eab26dc85ab6c86992c700cd3f4a597d9ed174b0e9c69489/azure_identity-1.25.1.tar.gz", hash = "sha256:87ca8328883de6036443e1c37b40e8dc8fb74898240f61071e09d2e369361456", size = 279826 }
|
| 241 |
+
wheels = [
|
| 242 |
+
{ url = "https://files.pythonhosted.org/packages/83/7b/5652771e24fff12da9dde4c20ecf4682e606b104f26419d139758cc935a6/azure_identity-1.25.1-py3-none-any.whl", hash = "sha256:e9edd720af03dff020223cd269fa3a61e8f345ea75443858273bcb44844ab651", size = 191317 },
|
| 243 |
+
]
|
| 244 |
+
|
| 245 |
[[package]]
|
| 246 |
name = "backports-tarfile"
|
| 247 |
version = "1.2.0"
|
|
|
|
| 761 |
{ name = "respx" },
|
| 762 |
{ name = "ruff" },
|
| 763 |
]
|
| 764 |
+
magentic = [
|
| 765 |
+
{ name = "agent-framework-core" },
|
| 766 |
+
]
|
| 767 |
|
| 768 |
[package.metadata]
|
| 769 |
requires-dist = [
|
| 770 |
+
{ name = "agent-framework-core", marker = "extra == 'magentic'", editable = "reference_repos/agent-framework/python/packages/core" },
|
| 771 |
{ name = "anthropic", specifier = ">=0.18.0" },
|
| 772 |
{ name = "beautifulsoup4", specifier = ">=4.12" },
|
| 773 |
{ name = "duckduckgo-search", specifier = ">=6.0" },
|
|
|
|
| 791 |
{ name = "tenacity", specifier = ">=8.2" },
|
| 792 |
{ name = "xmltodict", specifier = ">=0.13" },
|
| 793 |
]
|
| 794 |
+
provides-extras = ["dev", "magentic"]
|
| 795 |
|
| 796 |
[[package]]
|
| 797 |
name = "diskcache"
|
|
|
|
| 1164 |
{ url = "https://files.pythonhosted.org/packages/27/79/28f295d5064750674014f50e3c2daf8dc233964c904d357ac2bd0e33fc31/groq-0.36.0-py3-none-any.whl", hash = "sha256:ac7eeae31a5c2e76d30ea678f0b1a9168ff906c4440f5ec3a42ac74d5b4fdb3c", size = 137279 },
|
| 1165 |
]
|
| 1166 |
|
| 1167 |
+
[[package]]
|
| 1168 |
+
name = "grpcio"
|
| 1169 |
+
version = "1.76.0"
|
| 1170 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1171 |
+
dependencies = [
|
| 1172 |
+
{ name = "typing-extensions" },
|
| 1173 |
+
]
|
| 1174 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b6/e0/318c1ce3ae5a17894d5791e87aea147587c9e702f24122cc7a5c8bbaeeb1/grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73", size = 12785182 }
|
| 1175 |
+
wheels = [
|
| 1176 |
+
{ url = "https://files.pythonhosted.org/packages/a0/00/8163a1beeb6971f66b4bbe6ac9457b97948beba8dd2fc8e1281dce7f79ec/grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a", size = 5843567 },
|
| 1177 |
+
{ url = "https://files.pythonhosted.org/packages/10/c1/934202f5cf335e6d852530ce14ddb0fef21be612ba9ecbbcbd4d748ca32d/grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c", size = 11848017 },
|
| 1178 |
+
{ url = "https://files.pythonhosted.org/packages/11/0b/8dec16b1863d74af6eb3543928600ec2195af49ca58b16334972f6775663/grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465", size = 6412027 },
|
| 1179 |
+
{ url = "https://files.pythonhosted.org/packages/d7/64/7b9e6e7ab910bea9d46f2c090380bab274a0b91fb0a2fe9b0cd399fffa12/grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48", size = 7075913 },
|
| 1180 |
+
{ url = "https://files.pythonhosted.org/packages/68/86/093c46e9546073cefa789bd76d44c5cb2abc824ca62af0c18be590ff13ba/grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da", size = 6615417 },
|
| 1181 |
+
{ url = "https://files.pythonhosted.org/packages/f7/b6/5709a3a68500a9c03da6fb71740dcdd5ef245e39266461a03f31a57036d8/grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397", size = 7199683 },
|
| 1182 |
+
{ url = "https://files.pythonhosted.org/packages/91/d3/4b1f2bf16ed52ce0b508161df3a2d186e4935379a159a834cb4a7d687429/grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749", size = 8163109 },
|
| 1183 |
+
{ url = "https://files.pythonhosted.org/packages/5c/61/d9043f95f5f4cf085ac5dd6137b469d41befb04bd80280952ffa2a4c3f12/grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00", size = 7626676 },
|
| 1184 |
+
{ url = "https://files.pythonhosted.org/packages/36/95/fd9a5152ca02d8881e4dd419cdd790e11805979f499a2e5b96488b85cf27/grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054", size = 3997688 },
|
| 1185 |
+
{ url = "https://files.pythonhosted.org/packages/60/9c/5c359c8d4c9176cfa3c61ecd4efe5affe1f38d9bae81e81ac7186b4c9cc8/grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d", size = 4709315 },
|
| 1186 |
+
{ url = "https://files.pythonhosted.org/packages/bf/05/8e29121994b8d959ffa0afd28996d452f291b48cfc0875619de0bde2c50c/grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8", size = 5799718 },
|
| 1187 |
+
{ url = "https://files.pythonhosted.org/packages/d9/75/11d0e66b3cdf998c996489581bdad8900db79ebd83513e45c19548f1cba4/grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280", size = 11825627 },
|
| 1188 |
+
{ url = "https://files.pythonhosted.org/packages/28/50/2f0aa0498bc188048f5d9504dcc5c2c24f2eb1a9337cd0fa09a61a2e75f0/grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4", size = 6359167 },
|
| 1189 |
+
{ url = "https://files.pythonhosted.org/packages/66/e5/bbf0bb97d29ede1d59d6588af40018cfc345b17ce979b7b45424628dc8bb/grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11", size = 7044267 },
|
| 1190 |
+
{ url = "https://files.pythonhosted.org/packages/f5/86/f6ec2164f743d9609691115ae8ece098c76b894ebe4f7c94a655c6b03e98/grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6", size = 6573963 },
|
| 1191 |
+
{ url = "https://files.pythonhosted.org/packages/60/bc/8d9d0d8505feccfdf38a766d262c71e73639c165b311c9457208b56d92ae/grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8", size = 7164484 },
|
| 1192 |
+
{ url = "https://files.pythonhosted.org/packages/67/e6/5d6c2fc10b95edf6df9b8f19cf10a34263b7fd48493936fffd5085521292/grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980", size = 8127777 },
|
| 1193 |
+
{ url = "https://files.pythonhosted.org/packages/3f/c8/dce8ff21c86abe025efe304d9e31fdb0deaaa3b502b6a78141080f206da0/grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882", size = 7594014 },
|
| 1194 |
+
{ url = "https://files.pythonhosted.org/packages/e0/42/ad28191ebf983a5d0ecef90bab66baa5a6b18f2bfdef9d0a63b1973d9f75/grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958", size = 3984750 },
|
| 1195 |
+
{ url = "https://files.pythonhosted.org/packages/9e/00/7bd478cbb851c04a48baccaa49b75abaa8e4122f7d86da797500cccdd771/grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347", size = 4704003 },
|
| 1196 |
+
{ url = "https://files.pythonhosted.org/packages/fc/ed/71467ab770effc9e8cef5f2e7388beb2be26ed642d567697bb103a790c72/grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2", size = 5807716 },
|
| 1197 |
+
{ url = "https://files.pythonhosted.org/packages/2c/85/c6ed56f9817fab03fa8a111ca91469941fb514e3e3ce6d793cb8f1e1347b/grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468", size = 11821522 },
|
| 1198 |
+
{ url = "https://files.pythonhosted.org/packages/ac/31/2b8a235ab40c39cbc141ef647f8a6eb7b0028f023015a4842933bc0d6831/grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3", size = 6362558 },
|
| 1199 |
+
{ url = "https://files.pythonhosted.org/packages/bd/64/9784eab483358e08847498ee56faf8ff6ea8e0a4592568d9f68edc97e9e9/grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb", size = 7049990 },
|
| 1200 |
+
{ url = "https://files.pythonhosted.org/packages/2b/94/8c12319a6369434e7a184b987e8e9f3b49a114c489b8315f029e24de4837/grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae", size = 6575387 },
|
| 1201 |
+
{ url = "https://files.pythonhosted.org/packages/15/0f/f12c32b03f731f4a6242f771f63039df182c8b8e2cf8075b245b409259d4/grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77", size = 7166668 },
|
| 1202 |
+
{ url = "https://files.pythonhosted.org/packages/ff/2d/3ec9ce0c2b1d92dd59d1c3264aaec9f0f7c817d6e8ac683b97198a36ed5a/grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03", size = 8124928 },
|
| 1203 |
+
{ url = "https://files.pythonhosted.org/packages/1a/74/fd3317be5672f4856bcdd1a9e7b5e17554692d3db9a3b273879dc02d657d/grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42", size = 7589983 },
|
| 1204 |
+
{ url = "https://files.pythonhosted.org/packages/45/bb/ca038cf420f405971f19821c8c15bcbc875505f6ffadafe9ffd77871dc4c/grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f", size = 3984727 },
|
| 1205 |
+
{ url = "https://files.pythonhosted.org/packages/41/80/84087dc56437ced7cdd4b13d7875e7439a52a261e3ab4e06488ba6173b0a/grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8", size = 4702799 },
|
| 1206 |
+
{ url = "https://files.pythonhosted.org/packages/b4/46/39adac80de49d678e6e073b70204091e76631e03e94928b9ea4ecf0f6e0e/grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62", size = 5808417 },
|
| 1207 |
+
{ url = "https://files.pythonhosted.org/packages/9c/f5/a4531f7fb8b4e2a60b94e39d5d924469b7a6988176b3422487be61fe2998/grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd", size = 11828219 },
|
| 1208 |
+
{ url = "https://files.pythonhosted.org/packages/4b/1c/de55d868ed7a8bd6acc6b1d6ddc4aa36d07a9f31d33c912c804adb1b971b/grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc", size = 6367826 },
|
| 1209 |
+
{ url = "https://files.pythonhosted.org/packages/59/64/99e44c02b5adb0ad13ab3adc89cb33cb54bfa90c74770f2607eea629b86f/grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a", size = 7049550 },
|
| 1210 |
+
{ url = "https://files.pythonhosted.org/packages/43/28/40a5be3f9a86949b83e7d6a2ad6011d993cbe9b6bd27bea881f61c7788b6/grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba", size = 6575564 },
|
| 1211 |
+
{ url = "https://files.pythonhosted.org/packages/4b/a9/1be18e6055b64467440208a8559afac243c66a8b904213af6f392dc2212f/grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09", size = 7176236 },
|
| 1212 |
+
{ url = "https://files.pythonhosted.org/packages/0f/55/dba05d3fcc151ce6e81327541d2cc8394f442f6b350fead67401661bf041/grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc", size = 8125795 },
|
| 1213 |
+
{ url = "https://files.pythonhosted.org/packages/4a/45/122df922d05655f63930cf42c9e3f72ba20aadb26c100ee105cad4ce4257/grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc", size = 7592214 },
|
| 1214 |
+
{ url = "https://files.pythonhosted.org/packages/4a/6e/0b899b7f6b66e5af39e377055fb4a6675c9ee28431df5708139df2e93233/grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e", size = 4062961 },
|
| 1215 |
+
{ url = "https://files.pythonhosted.org/packages/19/41/0b430b01a2eb38ee887f88c1f07644a1df8e289353b78e82b37ef988fb64/grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e", size = 4834462 },
|
| 1216 |
+
]
|
| 1217 |
+
|
| 1218 |
[[package]]
|
| 1219 |
name = "h11"
|
| 1220 |
version = "0.16.0"
|
|
|
|
| 1815 |
{ url = "https://files.pythonhosted.org/packages/a9/bb/711099f9c6bb52770f56e56401cdfb10da5b67029f701e0df29362df4c8e/mcp-1.22.0-py3-none-any.whl", hash = "sha256:bed758e24df1ed6846989c909ba4e3df339a27b4f30f1b8b627862a4bade4e98", size = 175489 },
|
| 1816 |
]
|
| 1817 |
|
| 1818 |
+
[package.optional-dependencies]
|
| 1819 |
+
ws = [
|
| 1820 |
+
{ name = "websockets" },
|
| 1821 |
+
]
|
| 1822 |
+
|
| 1823 |
[[package]]
|
| 1824 |
name = "mdurl"
|
| 1825 |
version = "0.1.2"
|
|
|
|
| 1856 |
{ url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 },
|
| 1857 |
]
|
| 1858 |
|
| 1859 |
+
[[package]]
|
| 1860 |
+
name = "msal"
|
| 1861 |
+
version = "1.34.0"
|
| 1862 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1863 |
+
dependencies = [
|
| 1864 |
+
{ name = "cryptography" },
|
| 1865 |
+
{ name = "pyjwt", extra = ["crypto"] },
|
| 1866 |
+
{ name = "requests" },
|
| 1867 |
+
]
|
| 1868 |
+
sdist = { url = "https://files.pythonhosted.org/packages/cf/0e/c857c46d653e104019a84f22d4494f2119b4fe9f896c92b4b864b3b045cc/msal-1.34.0.tar.gz", hash = "sha256:76ba83b716ea5a6d75b0279c0ac353a0e05b820ca1f6682c0eb7f45190c43c2f", size = 153961 }
|
| 1869 |
+
wheels = [
|
| 1870 |
+
{ url = "https://files.pythonhosted.org/packages/c2/dc/18d48843499e278538890dc709e9ee3dea8375f8be8e82682851df1b48b5/msal-1.34.0-py3-none-any.whl", hash = "sha256:f669b1644e4950115da7a176441b0e13ec2975c29528d8b9e81316023676d6e1", size = 116987 },
|
| 1871 |
+
]
|
| 1872 |
+
|
| 1873 |
+
[[package]]
|
| 1874 |
+
name = "msal-extensions"
|
| 1875 |
+
version = "1.3.1"
|
| 1876 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1877 |
+
dependencies = [
|
| 1878 |
+
{ name = "msal" },
|
| 1879 |
+
]
|
| 1880 |
+
sdist = { url = "https://files.pythonhosted.org/packages/01/99/5d239b6156eddf761a636bded1118414d161bd6b7b37a9335549ed159396/msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4", size = 23315 }
|
| 1881 |
+
wheels = [
|
| 1882 |
+
{ url = "https://files.pythonhosted.org/packages/5e/75/bd9b7bb966668920f06b200e84454c8f3566b102183bc55c5473d96cb2b9/msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca", size = 20583 },
|
| 1883 |
+
]
|
| 1884 |
+
|
| 1885 |
[[package]]
|
| 1886 |
name = "mypy"
|
| 1887 |
version = "1.18.2"
|
|
|
|
| 2087 |
{ url = "https://files.pythonhosted.org/packages/a7/9e/55a41c9601191e8cd8eb626b54ee6827b9c9d4a46d736f32abc80d8039fc/opentelemetry_exporter_otlp_proto_common-1.38.0-py3-none-any.whl", hash = "sha256:03cb76ab213300fe4f4c62b7d8f17d97fcfd21b89f0b5ce38ea156327ddda74a", size = 18359 },
|
| 2088 |
]
|
| 2089 |
|
| 2090 |
+
[[package]]
|
| 2091 |
+
name = "opentelemetry-exporter-otlp-proto-grpc"
|
| 2092 |
+
version = "1.38.0"
|
| 2093 |
+
source = { registry = "https://pypi.org/simple" }
|
| 2094 |
+
dependencies = [
|
| 2095 |
+
{ name = "googleapis-common-protos" },
|
| 2096 |
+
{ name = "grpcio" },
|
| 2097 |
+
{ name = "opentelemetry-api" },
|
| 2098 |
+
{ name = "opentelemetry-exporter-otlp-proto-common" },
|
| 2099 |
+
{ name = "opentelemetry-proto" },
|
| 2100 |
+
{ name = "opentelemetry-sdk" },
|
| 2101 |
+
{ name = "typing-extensions" },
|
| 2102 |
+
]
|
| 2103 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a2/c0/43222f5b97dc10812bc4f0abc5dc7cd0a2525a91b5151d26c9e2e958f52e/opentelemetry_exporter_otlp_proto_grpc-1.38.0.tar.gz", hash = "sha256:2473935e9eac71f401de6101d37d6f3f0f1831db92b953c7dcc912536158ebd6", size = 24676 }
|
| 2104 |
+
wheels = [
|
| 2105 |
+
{ url = "https://files.pythonhosted.org/packages/28/f0/bd831afbdba74ca2ce3982142a2fad707f8c487e8a3b6fef01f1d5945d1b/opentelemetry_exporter_otlp_proto_grpc-1.38.0-py3-none-any.whl", hash = "sha256:7c49fd9b4bd0dbe9ba13d91f764c2d20b0025649a6e4ac35792fb8d84d764bc7", size = 19695 },
|
| 2106 |
+
]
|
| 2107 |
+
|
| 2108 |
[[package]]
|
| 2109 |
name = "opentelemetry-exporter-otlp-proto-http"
|
| 2110 |
version = "1.38.0"
|
|
|
|
| 2193 |
{ url = "https://files.pythonhosted.org/packages/24/7d/c88d7b15ba8fe5c6b8f93be50fc11795e9fc05386c44afaf6b76fe191f9b/opentelemetry_semantic_conventions-0.59b0-py3-none-any.whl", hash = "sha256:35d3b8833ef97d614136e253c1da9342b4c3c083bbaf29ce31d572a1c3825eed", size = 207954 },
|
| 2194 |
]
|
| 2195 |
|
| 2196 |
+
[[package]]
|
| 2197 |
+
name = "opentelemetry-semantic-conventions-ai"
|
| 2198 |
+
version = "0.4.13"
|
| 2199 |
+
source = { registry = "https://pypi.org/simple" }
|
| 2200 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ba/e6/40b59eda51ac47009fb47afcdf37c6938594a0bd7f3b9fadcbc6058248e3/opentelemetry_semantic_conventions_ai-0.4.13.tar.gz", hash = "sha256:94efa9fb4ffac18c45f54a3a338ffeb7eedb7e1bb4d147786e77202e159f0036", size = 5368 }
|
| 2201 |
+
wheels = [
|
| 2202 |
+
{ url = "https://files.pythonhosted.org/packages/35/b5/cf25da2218910f0d6cdf7f876a06bed118c4969eacaf60a887cbaef44f44/opentelemetry_semantic_conventions_ai-0.4.13-py3-none-any.whl", hash = "sha256:883a30a6bb5deaec0d646912b5f9f6dcbb9f6f72557b73d0f2560bf25d13e2d5", size = 6080 },
|
| 2203 |
+
]
|
| 2204 |
+
|
| 2205 |
[[package]]
|
| 2206 |
name = "opentelemetry-util-http"
|
| 2207 |
version = "0.59b0"
|