Skip to content

Commit 58f0adb

Browse files
committed
- Add name, position, color fields to agents (backend + frontend)
- Replace 3D character buttons with styled AgentButton components - Add draggable/resizable floating chat panel (no Dialog overlay) - Collapsible session history sidebar, closed by default - 3D GLTF character renders on top of clicked agent button - Context-aware chat with page location indicator - Agent Island config in AI Settings with GM pre-selected - Workspace teardown endpoint for vector DB cleanup - Color picker and position field in agent config modal
1 parent d1e193b commit 58f0adb

54 files changed

Lines changed: 1744 additions & 555 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
357 Bytes
Binary file not shown.
1.75 KB
Binary file not shown.

agent-platform/api/agents.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class AgentResponse(BaseModel):
3939
user_id: str
4040
name: str
4141
type: str
42+
position: str = ""
43+
color: str = ""
4244
model_mode: str
4345
model_provider: str | None = None
4446
model_name: str | None = None
@@ -57,6 +59,8 @@ class AgentCreateRequest(BaseModel):
5759
workspace_id: str
5860
name: str
5961
type: str = "custom"
62+
position: str = ""
63+
color: str = ""
6064
model_mode: str = "auto"
6165
model_provider: str | None = None
6266
model_name: str | None = None
@@ -70,6 +74,8 @@ class AgentCreateRequest(BaseModel):
7074

7175
class AgentUpdateRequest(BaseModel):
7276
name: str | None = None
77+
position: str | None = None
78+
color: str | None = None
7379
model_mode: str | None = None
7480
model_provider: str | None = None
7581
model_name: str | None = None
@@ -168,6 +174,8 @@ def _to_response(agent_data: dict) -> AgentResponse:
168174
user_id=agent_data.get("userId", ""),
169175
name=agent_data.get("name", ""),
170176
type=agent_data.get("type", "custom"),
177+
position=agent_data.get("position", ""),
178+
color=agent_data.get("color", ""),
171179
model_mode=agent_data.get("modelMode", "auto"),
172180
model_provider=agent_data.get("modelProvider"),
173181
model_name=agent_data.get("modelName"),

agent-platform/api/workspaces.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from fastapi import APIRouter, Depends, status
44
from pydantic import BaseModel
55

6+
from google.cloud.firestore_v1.base_query import FieldFilter
7+
68
from core.firestore import get_firestore_client
79
from core.exceptions import AppError, NotFoundError
810
from services.auth import AuthedUser, get_current_user
@@ -106,6 +108,47 @@ def setup_workspace(
106108
)
107109

108110

111+
@router.delete("/{workspace_id}/teardown", status_code=status.HTTP_204_NO_CONTENT)
112+
def teardown_workspace(
113+
workspace_id: str,
114+
current_user: AuthedUser = Depends(get_current_user),
115+
) -> None:
116+
"""Clean up agent-platform resources for a workspace being deleted.
117+
118+
Deletes: all agents, all sessions, and the Qdrant collection.
119+
Called by the frontend before deleting the workspace doc from Firestore.
120+
"""
121+
db = get_firestore_client()
122+
policy = PolicyEngine(db)
123+
policy.assert_workspace_owner(current_user.firebase_uid, workspace_id)
124+
125+
# 1. Delete all sessions for this workspace
126+
session_docs = (
127+
db.collection("sessions")
128+
.where(filter=FieldFilter("workspaceId", "==", workspace_id))
129+
.stream()
130+
)
131+
for doc in session_docs:
132+
doc.reference.delete()
133+
134+
# 2. Delete all agents for this workspace
135+
agent_docs = (
136+
db.collection("agents")
137+
.where(filter=FieldFilter("workspaceId", "==", workspace_id))
138+
.stream()
139+
)
140+
for doc in agent_docs:
141+
doc.reference.delete()
142+
143+
# 3. Delete Qdrant collection (best-effort)
144+
try:
145+
qdrant = get_qdrant_client()
146+
collection_name = f"workspace_{workspace_id}"
147+
qdrant.delete_collection(collection_name)
148+
except Exception:
149+
logger.warning("Failed to delete Qdrant collection for workspace %s (may not exist)", workspace_id)
150+
151+
109152
@router.get("/{workspace_id}", response_model=WorkspaceResponse)
110153
def get_workspace(
111154
workspace_id: str,

agent-platform/architecture.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ agent-platform/
9797

9898
### agents.py — Agent Management
9999
- CRUD operations on `agents` Firestore collection
100-
- `create_default_gm_agent()`: Creates General Manager agent (isDefault=true, isOrchestrator=true)
100+
- `create_default_gm_agent()`: Creates GM agent named "Jeana" with position "General Manager" (isDefault=true, isOrchestrator=true)
101101
- Agent fields: name, type (gm|custom), modelMode, modelProvider, modelName, context (system prompt), skills, appAccess, mcpServers, orchestratorConfig
102102
- Cannot delete default agents
103103

@@ -327,6 +327,7 @@ POST /workspaces/setup {workspace_id, name}
327327
### agents/{agentId}
328328
```
329329
workspaceId, userId, name, type ("gm"|"custom")
330+
position (string, e.g. "General Manager"), color (hex string, e.g. "#6366f1")
330331
modelMode ("auto"|"manual"), modelProvider, modelName
331332
skills[], context (system prompt)
332333
isDefault, isOrchestrator
187 Bytes
Binary file not shown.

agent-platform/services/agents.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99

1010

1111
DEFAULT_GM_AGENT = {
12-
"name": "General Manager",
12+
"name": "Jeana",
1313
"type": "gm",
14+
"position": "General Manager",
15+
"color": "#a855f7",
1416
"modelMode": "auto",
1517
"modelProvider": None,
1618
"modelName": None,
@@ -37,6 +39,8 @@ def create_agent(db: Client, workspace_id: str, user_id: str, data: dict) -> dic
3739
"userId": user_id,
3840
"name": data.get("name", "New Agent"),
3941
"type": data.get("type", "custom"),
42+
"position": data.get("position", ""),
43+
"color": data.get("color", ""),
4044
"modelMode": data.get("modelMode", "auto"),
4145
"modelProvider": data.get("modelProvider"),
4246
"modelName": data.get("modelName"),
@@ -94,8 +98,9 @@ def update_agent(db: Client, agent_id: str, updates: dict) -> dict:
9498
raise NotFoundError("agent", agent_id)
9599

96100
allowed_fields = {
97-
"name", "modelMode", "modelProvider", "modelName", "skills", "context",
98-
"isOrchestrator", "appAccess", "mcpServers", "orchestratorConfig",
101+
"name", "position", "color", "modelMode", "modelProvider", "modelName",
102+
"skills", "context", "isOrchestrator", "appAccess", "mcpServers",
103+
"orchestratorConfig",
99104
}
100105
filtered = {k: v for k, v in updates.items() if k in allowed_fields}
101106
filtered["updatedAt"] = datetime.now(timezone.utc)
Binary file not shown.

agent-platform/tests/test_agents.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ def test_get_agent(client):
3030
assert resp.status_code == 200
3131
data = resp.json()
3232
assert data["id"] == gm_id
33-
assert data["name"] == "General Manager"
33+
assert data["name"] == "Jeana"
34+
assert data["position"] == "General Manager"
35+
assert data["color"] == "#a855f7"
3436

3537

3638
def test_create_custom_agent(client):

app/architecture.md

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ app/src/
4343
├── components/ # Reusable UI components
4444
│ ├── ui/ # Generic Shadcn primitives (button, card, dialog, accordion, etc.)
4545
│ ├── ai-elements/ # Conversation, Message, PromptInput components
46-
│ ├── AgentIsland/ # 3D agent bar (React Three Fiber)
46+
│ ├── AgentIsland/ # Floating agent bar with chat modal
4747
│ ├── AgentSettings/ # AgentConfigModal
4848
│ ├── Board/ # PyramidBoard, Block, BlockModal
4949
│ ├── Chat/ # (reserved for future chat components)
@@ -188,44 +188,47 @@ pyramids, productDefinitions, contextDocuments, directories, uiUxArchitectures,
188188
| Path | Page | Description |
189189
|------|------|-------------|
190190
| `/workspaces` | WorkspacesPage | Workspace list and creation |
191-
| `/workspace/:id/dashboard` | Dashboard | Main app selector (8 categories) |
191+
192+
All workspace-scoped routes are nested under `/:workspaceId` using a `WorkspaceRouteSync` layout route that syncs the URL workspace ID to context.
193+
194+
| `/:workspaceId/dashboard` | Dashboard | Main app selector (8 categories) |
192195

193196
#### Problem Solving, Thinking and Planning (bg-indigo-600)
194197
| Path | Page | Description |
195198
|------|------|-------------|
196-
| `/pyramids` | PyramidsPage | Pyramid list |
197-
| `/pyramid/:id` | PyramidEditor | 8x8 grid editor |
198-
| `/diagrams` | DiagramsPage | Diagram list |
199-
| `/diagram/:id` | DiagramEditor | ReactFlow visual editor |
199+
| `/:workspaceId/pyramids` | PyramidsPage | Pyramid list |
200+
| `/:workspaceId/pyramid/:id` | PyramidEditor | 8x8 grid editor |
201+
| `/:workspaceId/diagrams` | DiagramsPage | Diagram list |
202+
| `/:workspaceId/diagram/:id` | DiagramEditor | ReactFlow visual editor |
200203

201204
#### Product Design & Management (bg-teal-600 / bg-pink-600)
202205
| Path | Page | Description |
203206
|------|------|-------------|
204-
| `/product-definitions` | ProductDefinitionsPage | Product def list |
205-
| `/product-definition/:id` | ProductDefinitionEditor | Hierarchical mindmap editor |
206-
| `/ui-ux-architectures` | UiUxArchitecturesPage | UI/UX list |
207-
| `/ui-ux-architecture/:id` | UiUxArchitectureEditorPage | Theme/component/page editor |
207+
| `/:workspaceId/product-definitions` | ProductDefinitionsPage | Product def list |
208+
| `/:workspaceId/product-definition/:id` | ProductDefinitionEditor | Hierarchical mindmap editor |
209+
| `/:workspaceId/ui-ux-architectures` | UiUxArchitecturesPage | UI/UX list |
210+
| `/:workspaceId/ui-ux-architecture/:id` | UiUxArchitectureEditorPage | Theme/component/page editor |
208211

209212
#### Knowledge Base (bg-amber-600)
210213
| Path | Page | Description |
211214
|------|------|-------------|
212-
| `/context-documents` | ContextDocumentsPage | Document list |
213-
| `/context-document/:id` | ContextDocumentEditor | Rich text editor |
214-
| `/directory/:id` | DirectoryDocumentsPage | Directory contents |
215+
| `/:workspaceId/context-documents` | ContextDocumentsPage | Document list |
216+
| `/:workspaceId/context-document/:id` | ContextDocumentEditor | Rich text editor |
217+
| `/:workspaceId/directory/:id` | DirectoryDocumentsPage | Directory contents |
215218

216219
#### Technical (bg-purple-600 / bg-blue-600)
217220
| Path | Page | Description |
218221
|------|------|-------------|
219-
| `/technical-architectures` | TechnicalArchitecturesPage | Architecture list |
220-
| `/technical-architecture/:id` | TechnicalArchitectureEditorPage | Architecture editor |
221-
| `/technical-tasks` | TechnicalTaskBoard | Kanban board |
222-
| `/technical-task/:id` | TechnicalTaskDetail | Task detail view |
222+
| `/:workspaceId/technical-architectures` | TechnicalArchitecturesPage | Architecture list |
223+
| `/:workspaceId/technical-architecture/:id` | TechnicalArchitectureEditorPage | Architecture editor |
224+
| `/:workspaceId/technical-tasks` | TechnicalTaskBoard | Kanban board |
225+
| `/:workspaceId/technical-task/:id` | TechnicalTaskDetail | Task detail view |
223226

224227
#### AI Apps (bg-violet-600)
225228
| Path | Page | Description |
226229
|------|------|-------------|
227-
| `/ai-chat` | AiChatPage | Session-based AI chat |
228-
| `/workspace/:id/ai-settings` | AiSettingsPage | Agent configuration |
230+
| `/:workspaceId/ai-chat` | AiChatPage | Session-based AI chat |
231+
| `/:workspaceId/ai-settings` | AiSettingsPage | Agent configuration |
229232

230233
---
231234

@@ -445,34 +448,39 @@ agents, sessions — writes via Admin SDK (bypasses rules)
445448
446449
## Agent Island (3D Agent Bar)
447450
448-
Global floating bar at center-bottom of all authenticated pages displaying workspace agents as interactive 3D characters.
451+
Floating glassmorphism bar at center-bottom of workspace pages. Agents rendered as blur-styled buttons with name, position, and color. Clicking an agent opens a per-agent chat modal.
449452
450453
### Component Tree
451454
```
452455
AuthenticatedLayout
453456
└── AgentIsland (fixed bottom-center, glassmorphism)
454-
└── React.lazyAgentCharacter × N
455-
└── <Canvas> (R3F)
456-
└── AgentModel (GLTF + animation cycling)
457+
├── AgentButton × N (blur/glass styled, color accent)
458+
├── "All Agents" button/ai-chat
459+
├── "AI Settings" button/ai-settings
460+
└── AgentChatModal (Dialog with chat session)
461+
└── useAgentChat hook (shared with AiChatPage)
457462
```
458463
459464
### Files
460465
| File | Purpose |
461466
|------|---------|
462-
| `components/AgentIsland/AgentIsland.tsx` | Container: glassmorphism bar, lazy loading, route-based visibility |
463-
| `components/AgentIsland/AgentCharacter.tsx` | Per-agent 3D Canvas with GLTF model and animation cycling |
467+
| `components/AgentIsland/AgentIsland.tsx` | Container: glassmorphism bar, visibility logic, modal state |
468+
| `components/AgentIsland/AgentButton.tsx` | Per-agent blur/glass button with color, name, position, status badge |
469+
| `components/AgentIsland/AgentChatModal.tsx` | Dialog with session sidebar + chat area for a specific agent |
464470
| `components/AgentIsland/useAgentIslandAgents.ts` | Hook: fetches agents via `getAgents(workspaceId)` |
471+
| `components/AgentIsland/useAgentLastSessionStatus.ts` | Hook: fetches last session status per agent |
472+
| `hooks/useAgentChat.ts` | Extracted chat logic shared between AgentChatModal and AiChatPage |
473+
| `lib/agent-colors.ts` | Color palette (12 colors) + `getRandomAgentColor()` helper |
465474
466-
### 3D Stack
467-
- **@react-three/fiber**: React renderer for Three.js
468-
- **@react-three/drei**: `useGLTF` (GLTF/Draco loading), `useAnimations` (clip management)
469-
- **Model**: `public/agents/gm.gltf` — shared model for all agents (Draco-compressed)
470-
- **Animations**: `idle`, `walk`, `happy`, `sad`, `standing_jump`, `jump_run`, `running`
475+
### Agent Data Model (new fields)
476+
- `position: string` — Agent role (e.g., "General Manager", "Designer")
477+
- `color: string` — Hex color from palette, used for button accent
478+
- Default GM agent: name "Jeana", position "General Manager", color "#6366f1"
471479
472480
### Behavior
473-
- Each agent rendered as a separate `<Canvas>` with transparent background
474-
- Characters overflow above the island container (upper body/head sticks out)
475-
- Animation cycle: `idle``walk``happy` with crossfade, staggered per agent
476-
- Click navigates to `/ai-chat`
477-
- Hidden on `/ai-chat` page, max 6 visible agents with "+N" overflow badge
478-
- Lazy-loaded to keep Three.js out of the initial JS bundle
481+
- Max 5 agents visible, configurable via `workspace.islandAgentIds` in AI Settings
482+
- Click agent → opens `AgentChatModal` (not navigation)
483+
- Right-side buttons: "All Agents" (→ /ai-chat), "AI Settings" (→ /ai-settings)
484+
- Status badge on agent buttons: green pulse = active session, amber = paused, none = no session
485+
- Hidden on `/ai-chat` page and `/workspaces` page
486+
- Context awareness: modal uses `useCurrentPageContext` to pass page context to agent

0 commit comments

Comments
 (0)