Skip to content

Commit 9b49efe

Browse files
committed
Integrate application updates without embedded secrets
1 parent 4be5eaf commit 9b49efe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+6180
-970
lines changed

.gitignore

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,13 @@ celerybeat.pid
109109
# SageMath parsed files
110110
*.sage.py
111111

112-
# Environments
112+
# Environments and secrets
113113
.env
114+
.env.*
115+
*.env
116+
*.key
117+
*.secret
118+
*.pem
114119
.venv
115120
.evalenv
116121
env/
@@ -119,6 +124,14 @@ ENV/
119124
env.bak/
120125
venv.bak/
121126

127+
# API keys and credentials
128+
*_key
129+
*_secret
130+
*_token
131+
credentials.json
132+
secrets.json
133+
agents/verify_credentials.py
134+
122135
# Spyder project settings
123136
.spyderproject
124137
.spyproject
@@ -153,4 +166,29 @@ data/**/*.md5
153166
!/data/.gitkeep
154167
!/data/README.md
155168

169+
# Large files and data
170+
*.pdf
171+
!tests/test-data/*.pdf
172+
*.zip
173+
*.tar.gz
174+
*.7z
175+
*.rar
176+
177+
# Cache and temporary files
178+
.cache/
179+
*.cache
180+
*.tmp
181+
*.temp
182+
*.swp
183+
*.swo
184+
*~
185+
186+
# OS files
156187
.DS_Store
188+
Thumbs.db
189+
desktop.ini
190+
191+
# IDE files
192+
.vscode/
193+
.idea/
194+
*.sublime-*

SECURITY.md

Lines changed: 0 additions & 41 deletions
This file was deleted.

agents/.deployment

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[config]
2+
SCM_DO_BUILD_DURING_DEPLOYMENT=true
3+
4+
5+
6+
7+

agents/.env.example

Lines changed: 0 additions & 30 deletions
This file was deleted.

agents/.env.test

Lines changed: 0 additions & 8 deletions
This file was deleted.

agents/adapters/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Adapters package
2+
3+
4+
5+
6+
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
"""
2+
Copilot-specific response adapter for formatting responses for Microsoft Copilot.
3+
This adapter formats RAG responses specifically for Copilot UI consumption.
4+
"""
5+
6+
import logging
7+
from typing import Dict, Any, List, Optional
8+
9+
from services.rag_service import RAGResponse
10+
from models.citation import Citation, CitationSource, resolve_citation_conflicts
11+
12+
13+
logger = logging.getLogger(__name__)
14+
15+
16+
class CopilotResponseAdapter:
17+
"""
18+
Response adapter for Microsoft Copilot plugin.
19+
Formats responses to be consumed by Copilot UI.
20+
"""
21+
22+
def __init__(self):
23+
logger.info("CopilotResponseAdapter initialized")
24+
25+
def format_rag_response(
26+
self,
27+
rag_response: RAGResponse,
28+
include_metadata: bool = True
29+
) -> Dict[str, Any]:
30+
"""
31+
Format a RAG response for Copilot.
32+
33+
Args:
34+
rag_response: RAG response from backend
35+
include_metadata: Whether to include token usage and model info
36+
37+
Returns:
38+
Formatted response dictionary for Copilot
39+
"""
40+
try:
41+
# Start with answer
42+
response = {
43+
"answer": rag_response.answer
44+
}
45+
46+
# Format citations
47+
citations = self._format_citations(rag_response)
48+
if citations:
49+
response["citations"] = citations
50+
51+
# Add sources (for Copilot's source tracking)
52+
sources = self._format_sources(rag_response)
53+
if sources:
54+
response["sources"] = sources
55+
56+
# Add thoughts if available
57+
if rag_response.thoughts:
58+
response["thoughts"] = [
59+
{
60+
"title": thought.get("title", ""),
61+
"description": thought.get("description", "")
62+
}
63+
for thought in rag_response.thoughts
64+
]
65+
66+
# Add metadata if requested
67+
if include_metadata:
68+
metadata = {}
69+
if rag_response.token_usage:
70+
metadata["token_usage"] = rag_response.token_usage
71+
if rag_response.model_info:
72+
metadata["model_info"] = rag_response.model_info
73+
if metadata:
74+
response["metadata"] = metadata
75+
76+
return response
77+
78+
except Exception as e:
79+
logger.error(f"Error formatting Copilot response: {e}", exc_info=True)
80+
return {
81+
"answer": rag_response.answer,
82+
"citations": [],
83+
"error": str(e)
84+
}
85+
86+
def _format_citations(
87+
self,
88+
rag_response: RAGResponse
89+
) -> List[Dict[str, Any]]:
90+
"""
91+
Format citations for Copilot.
92+
Uses unified citations if available, falls back to legacy format.
93+
"""
94+
citations = []
95+
96+
# Prefer unified citations
97+
if rag_response.unified_citations:
98+
# Resolve conflicts (prefer corpus)
99+
resolved = resolve_citation_conflicts(
100+
rag_response.unified_citations,
101+
prefer_corpus=True
102+
)
103+
104+
for citation in resolved:
105+
citations.append({
106+
"title": citation.title,
107+
"url": citation.url,
108+
"snippet": citation.snippet[:300] if citation.snippet else "",
109+
"source": citation.source.value,
110+
"provider": citation.provider.value,
111+
"confidence": citation.confidence
112+
})
113+
else:
114+
# Fallback to legacy citations
115+
for citation_str in rag_response.citations:
116+
if citation_str:
117+
citations.append({
118+
"title": citation_str[:100],
119+
"url": "",
120+
"snippet": citation_str,
121+
"source": "unknown",
122+
"provider": "unknown"
123+
})
124+
125+
return citations
126+
127+
def _format_sources(
128+
self,
129+
rag_response: RAGResponse
130+
) -> List[Dict[str, Any]]:
131+
"""
132+
Format sources for Copilot's source tracking.
133+
"""
134+
sources = []
135+
136+
# Add sources from rag_response.sources
137+
for source in rag_response.sources:
138+
if isinstance(source, dict):
139+
sources.append({
140+
"title": source.get("title", source.get("sourcefile", "Document")),
141+
"url": source.get("url", source.get("sourcepage", "")),
142+
"type": "document"
143+
})
144+
145+
return sources
146+
147+
def format_search_results(
148+
self,
149+
results: List[Dict[str, Any]],
150+
query: str
151+
) -> Dict[str, Any]:
152+
"""
153+
Format search results for Copilot search endpoint.
154+
"""
155+
formatted_results = []
156+
157+
for result in results:
158+
formatted_results.append({
159+
"title": result.get("title", "Document"),
160+
"url": result.get("url", ""),
161+
"snippet": result.get("snippet", result.get("content", ""))[:300],
162+
"source": result.get("source", "corpus")
163+
})
164+
165+
return {
166+
"results": formatted_results,
167+
"totalCount": len(formatted_results),
168+
"query": query
169+
}
170+
171+
def format_error_response(
172+
self,
173+
error_message: str,
174+
error_code: Optional[str] = None
175+
) -> Dict[str, Any]:
176+
"""
177+
Format error response for Copilot.
178+
"""
179+
response = {
180+
"answer": f"I encountered an error: {error_message}",
181+
"citations": [],
182+
"error": error_message
183+
}
184+
185+
if error_code:
186+
response["error_code"] = error_code
187+
188+
return response
189+
190+
191+
192+
193+

0 commit comments

Comments
 (0)