Skip to content

Commit 9a647c7

Browse files
committed
end of day commit
1 parent a802ca4 commit 9a647c7

File tree

6 files changed

+148
-23
lines changed

6 files changed

+148
-23
lines changed

data/agent_teams/hr.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "3",
33
"team_id": "team-3",
4-
"name": "Retail Customer Success Team",
4+
"name": "Human Resources Team",
55
"status": "visible",
66
"created": "",
77
"created_by": "",

data/agent_teams/new 29.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Tasks:
2+
3+
Done: Make 3 teams upload work to cosmos (HR, Marketing, Retail). We will load this Cosmos data on deploy as default teams.
4+
Done: - call "/socket/{process_id}" (start_comms) to setup websocket
5+
Done: Make sure that a team is always selected - start with the hr.json team
6+
7+
call init_team API for the currently loaded team on App start -
8+
Spinner / team-loading should display until this call returns (user should not be able to input tasks)
9+
<takes about 20 seconds> - say something like "team loading" with spinner
10+
FE: send unload current team API and call init team for team switch - sending select_team(new team id)
11+
spin while waiting for return of API
12+
BE: unload old team - load new team - return status
13+
14+
BE: For Francia - implement get_plans to fill in history from cosmos
15+
16+
BE: Create a teams container in Cosmos and move all loaded team definitions there
17+
18+
Implement saving of plan to cosmos -> history in...
19+
20+
================ Request submit flow ======================
21+
on request submission call "/create_plan" (process_request)
22+
This will return immediately - move to other page and display spinner -> "creating plan"
23+
Socket will start receiving messages ->
24+
Stream plan output into main window
25+
26+
Will receive the PlanApprovalRequest message
27+
Enable accept / reject UI
28+
Send PlanApprovalResponse message when user answers
29+
30+
If not approved
31+
BE: plan will cancel on backend
32+
FE: - enable input again for fresh request
33+
Call input_request API on backend again (just like inputing any request)
34+
35+
If approved:
36+
Display plan steps in right pane if approved
37+
=============================================================
38+
39+
================== Message Streaming ========================
40+
Process socket message routing to display agent output
41+
See message types in src\backend\v3\models\messages.py
42+
for each message from agent - process stream then rollup
43+
44+
On FinalResultMessage
45+
display final result with all agent output in rollups by agent above
46+
==============================================================
47+
48+

src/backend/app_kernel.py

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -102,27 +102,27 @@
102102
# connection_config.add_connection(process_id=process_id, connection=websocket)
103103

104104
@app.websocket("/socket/{process_id}")
105-
async def process_outputs(websocket: WebSocket, process_id: str):
105+
async def start_comms(websocket: WebSocket, process_id: str):
106106
""" Web-Socket endpoint for real-time process status updates. """
107107

108108
# Always accept the WebSocket connection first
109109
await websocket.accept()
110110

111-
# user_id = None
112-
# try:
113-
# # WebSocket headers are different, try to get user info
114-
# headers = dict(websocket.headers)
115-
# authenticated_user = get_authenticated_user_details(request_headers=headers)
116-
# user_id = authenticated_user.get("user_principal_id")
117-
# if not user_id:
118-
# user_id = f"anonymous_{process_id}"
119-
# except Exception as e:
120-
# logging.warning(f"Could not extract user from WebSocket headers: {e}")
121-
# user_id = f"anonymous_{user_id}"
111+
user_id = None
112+
try:
113+
# WebSocket headers are different, try to get user info
114+
headers = dict(websocket.headers)
115+
authenticated_user = get_authenticated_user_details(request_headers=headers)
116+
user_id = authenticated_user.get("user_principal_id")
117+
if not user_id:
118+
user_id = f"anonymous_{process_id}"
119+
except Exception as e:
120+
logging.warning(f"Could not extract user from WebSocket headers: {e}")
121+
user_id = f"anonymous_{user_id}"
122122

123123
# Add to the connection manager for backend updates
124124

125-
connection_config.add_connection(process_id, websocket)
125+
connection_config.add_connection(user_id, websocket)
126126
track_event_if_configured("WebSocketConnectionAccepted", {"process_id": "user_id"})
127127

128128
# Keep the connection open - FastAPI will close the connection if this returns
@@ -135,8 +135,8 @@ async def process_outputs(websocket: WebSocket, process_id: str):
135135
pass
136136

137137
except WebSocketDisconnect:
138-
track_event_if_configured("WebSocketDisconnect", {"process_id": user_id})
139-
logging.info(f"Client disconnected from batch {user_id}")
138+
track_event_if_configured("WebSocketDisconnect", {"process_id": process_id})
139+
logging.info(f"Client disconnected from batch {process_id}")
140140
await connection_config.close_connection(user_id)
141141
except Exception as e:
142142
logging.error("Error in WebSocket connection", error=str(e))
@@ -726,10 +726,7 @@ async def get_plans(
726726

727727
await connection_config.send_status_update_async("Test message from get_plans", user_id)
728728

729-
# Initialize agent team for this user session
730-
#await OrchestrationManager.get_current_orchestration(user_id=user_id)
731-
732-
# Replace the following with code to get plan run history from the database
729+
#### <To do: Francia> Replace the following with code to get plan run history from the database
733730

734731
# # Initialize memory context
735732
# memory_store = await DatabaseFactory.get_database(user_id=user_id)
@@ -786,7 +783,21 @@ async def get_plans(
786783

787784
return []
788785

789-
786+
@app.get("/api/init_team")
787+
async def init_team(
788+
request: Request,
789+
):
790+
""" Initialize the team of agents """
791+
authenticated_user = get_authenticated_user_details(request_headers=request.headers)
792+
user_id = authenticated_user["user_principal_id"]
793+
if not user_id:
794+
track_event_if_configured(
795+
"UserIdNotFound", {"status_code": 400, "detail": "no user"}
796+
)
797+
raise HTTPException(status_code=400, detail="no user")
798+
# Initialize agent team for this user session
799+
await OrchestrationManager.get_current_orchestration(user_id=user_id)
800+
790801
@app.get("/api/steps/{plan_id}", response_model=List[Step])
791802
async def get_steps_by_plan(plan_id: str, request: Request) -> List[Step]:
792803
"""

src/backend/v3/api/router.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ async def process_request(background_tasks: BackgroundTasks, input_task: InputTa
8686
type: string
8787
description: Error message
8888
"""
89-
await connection_config.send_status_update_async(message="sending test from the server", process_id='12345')
89+
9090

9191
# if not await rai_success(input_task.description, False):
9292
# track_event_if_configured(
@@ -133,6 +133,7 @@ async def process_request(background_tasks: BackgroundTasks, input_task: InputTa
133133

134134
try:
135135
#background_tasks.add_task(OrchestrationManager.run_orchestration, user_id, input_task)
136+
await connection_config.send_status_update_async("Test message from process_request", user_id)
136137

137138
return {
138139
"status": "Request started successfully",

src/backend/v3/models/messages.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""Messages from the backend to the frontend via WebSocket."""
2+
3+
from dataclasses import dataclass
4+
5+
from models import MPlan, PlanStatus
6+
7+
8+
@dataclass(slots=True)
9+
class AgentMessage:
10+
"""Message from the backend to the frontend via WebSocket."""
11+
agent_name: str
12+
timestamp: str
13+
content: str
14+
15+
@dataclass(slots=True)
16+
class AgentMessageStreaming:
17+
"""Streaming message from the backend to the frontend via WebSocket."""
18+
agent_name: str
19+
content: str
20+
is_final: bool = False
21+
22+
@dataclass(slots=True)
23+
class PlanApprovalRequest:
24+
"""Request for plan approval from the frontend."""
25+
plan: MPlan
26+
status: PlanStatus
27+
28+
context: dict | None = None
29+
30+
@dataclass(slots=True)
31+
class PlanApprovalResponse:
32+
"""Response for plan approval from the frontend."""
33+
approved: bool
34+
feedback: str | None = None
35+
36+
@dataclass(slots=True)
37+
class ReplanApprovalRequest:
38+
"""Request for replan approval from the frontend."""
39+
reason: str
40+
context: dict | None = None
41+
42+
@dataclass(slots=True)
43+
class ReplanApprovalResponse:
44+
"""Response for replan approval from the frontend."""
45+
approved: bool
46+
feedback: str | None = None
47+
48+
@dataclass(slots=True)
49+
class UserClarificationRequest:
50+
"""Request for user clarification from the frontend."""
51+
question: str
52+
context: dict | None = None
53+
54+
@dataclass(slots=True)
55+
class UserClarificationResponse:
56+
"""Response for user clarification from the frontend."""
57+
def __init__(self, answer: str):
58+
self.answer = answer
59+
60+
@dataclass(slots=True)
61+
class FinalResultMessage:
62+
"""Final result message from the backend to the frontend."""
63+
result: str
64+
summary: str | None = None
65+
context: dict | None = None

src/frontend/src/services/WebSocketService.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class WebSocketService {
3737
// Get WebSocket URL from environment or default to localhost
3838
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
3939
const wsHost = process.env.REACT_APP_WS_HOST || '127.0.0.1:8000';
40-
const processId = '12345'; // Replace with actual process ID as needed'
40+
const processId = crypto.randomUUID(); // Replace with actual process ID as needed'
4141
const wsUrl = `${wsProtocol}//${wsHost}/socket/${processId}`;
4242

4343
console.log('Connecting to WebSocket:', wsUrl);

0 commit comments

Comments
 (0)