### Backend Setup: Start FastAPI Server Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/README.md Starts the FastAPI backend server for the Cymbal Bank Orchestra platform. Requires environment variables to be set, including GOOGLE_API_KEY. ```bash ./start.sh # The backend will be available at http://localhost:8001 ``` -------------------------------- ### Backend Setup: Install Python Dependencies Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/README.md Installs the necessary Python packages for the backend application from the requirements.txt file. Ensure you have Python 3.9+ installed. ```bash cd backend/no-name-agent pip install -r requirements.txt ``` -------------------------------- ### Run Development Server with npm Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/README.md Starts the development server for the AI Studio app. This command assumes dependencies are installed and the GEMINI_API_KEY is set in .env.local. It allows for local testing and development. ```bash npm run dev ``` -------------------------------- ### Frontend Setup: Install Node.js Dependencies Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/README.md Installs the required Node.js packages for the React frontend using npm. Ensure Node.js 16+ is installed. ```bash cd frontend npm install ``` -------------------------------- ### Frontend Setup: Start Vite Development Server Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/README.md Starts the Vite development server for the React frontend. This command also enables the use of npm run dev as an alternative. ```bash ./start.sh # or npm run dev # The frontend will be available at http://localhost:5173 ``` -------------------------------- ### Install Dependencies with npm Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/README.md Installs all necessary project dependencies using npm. This is a prerequisite for running the application locally. Ensure Node.js and npm are installed. ```bash npm install ``` -------------------------------- ### Context Generation Example in Cymbal Bank Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/docs/DEMO_INTEGRATION.md Illustrates the automatically generated context that includes the user's ID and permission limitations before a user's message is processed. This context is crucial for the agent to respond appropriately without direct UI interaction. ```text The user's ID is Marcus. You must never ask for the user for their name or ID. Always assume their user ID is Marcus. Permission Context: You do not have access to the user's transaction history. You do not have access to the user's debt information. Please respect these limitations when responding to user queries. User message: [actual user message] ``` -------------------------------- ### Start Agent Session for Financial Agents Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This asynchronous function initializes an agent session within the application. It supports multiple financial agents ('investments_agent', 'daily_spendings_agent', etc.) or a default 'root_agent'. The session is configured for either audio or text modality and returns live event streams and a request queue for real-time interaction. Dependencies include 'InMemoryRunner', 'RunConfig', 'LiveRequestQueue', and various agent definitions. ```python async def start_agent_session(user_id, is_audio=False, agent_id=None): """Initialize agent session with specified configuration""" agent_map = { "investments_agent": investments_agent, "daily_spendings_agent": daily_spendings_agent, "financial_agent": financial_agent, "transaction_history_agent": transaction_history_agent } runner = InMemoryRunner( app_name="ADK Streaming example", agent=agent_map.get(agent_id, root_agent) ) session = await runner.session_service.create_session( app_name="ADK Streaming example", user_id=user_id ) modality = "AUDIO" if is_audio else "TEXT" run_config = RunConfig(response_modalities=[modality]) live_request_queue = LiveRequestQueue() live_events = runner.run_live( session=session, live_request_queue=live_request_queue, run_config=run_config ) return live_events, live_request_queue ``` -------------------------------- ### Fetch User Transaction History via FastAPI Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This Python code snippet shows how to make a GET request to a FastAPI endpoint to retrieve a user's transaction history. It uses the `requests` library and expects a JSON response. Error handling is included for non-200 status codes. The expected response format is a list of transaction objects. ```python import requests import json # GET request to fetch transaction history response = requests.get( 'http://localhost:8001/api/transaction-history/user-001', headers={'Content-Type': 'application/json'} ) if response.status_code == 200: transactions = response.json() for transaction in transactions: print(f"{transaction['Date']}: {transaction['Description']} - ${transaction['Amount']}") else: error = response.json() print(f"Error: {error['error']}") # Expected response format: # [ # { # "Transaction ID": "txn-001", # "Account ID": "acc-user-001-checking", # "Date": "2025-10-15", # "Description": "Coffee Shop", # "Amount": -4.50, # "Category": "Food & Dining" # }, # ... # ] ``` -------------------------------- ### Calendar Agent for Google Calendar Integration (Python) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This Python agent manages appointments and calendar events by integrating with the Google Calendar API. It provides functions to get the current time, list upcoming events within a specified date range, and create new events. Dependencies include google.adk.agents and datetime. ```python from google.adk.agents import Agent import datetime def get_current_time() -> dict: """Get current date and time""" now = datetime.datetime.now() return { "current_time": now.strftime("%Y-%m-%d %H:%M:%S"), "formatted_date": now.strftime("%m-%d-%Y") } def list_events(start_date: str, days: int) -> dict: """ List upcoming calendar events within a date range. Args: start_date: Start date in YYYY-MM-DD format (empty string for today) days: Number of days to look ahead (1 for today, 7 for week, 30 for month) Returns: Dictionary with status and list of events """ service = get_calendar_service() # Assuming get_calendar_service is defined elsewhere # ... implementation ... return { "status": "success", "message": "Found 3 event(s)", "events": [ { "id": "evt123", "summary": "Financial Advisor Meeting", "start": "2025-10-22 10:00 AM", "end": "2025-10-22 11:00 AM", "link": "https://calendar.google.com/event?eid=..." } ] } def create_event(summary: str, start_time: str, end_time: str) -> dict: """ Create a new calendar event. Args: summary: Event title start_time: Start time as "YYYY-MM-DD HH:MM" end_time: End time as "YYYY-MM-DD HH:MM" """ # ... implementation ... return { "status": "success", "message": "Event created successfully", "event_id": "evt456", "event_link": "https://calendar.google.com/event?eid=..." } calendar_agent = Agent( name="jarvis", model="gemini-2.0-flash-exp", description="Agent for scheduling and calendar operations", instruction=f""" You can perform calendar operations: - list_events: Show events for a time period - create_event: Add new event - edit_event: Modify existing event - delete_event: Remove event Be proactive - use defaults when context is clear. Today's date is {get_current_time()}. """, tools=[list_events, create_event, edit_event, delete_event] # Assuming edit_event and delete_event are defined elsewhere ) # Example usage: # User: "What's on my calendar today?" # Agent calls: list_events(start_date="", days=1) # User: "Book a meeting with my financial advisor tomorrow at 2pm" # Agent calls: create_event( # summary="Financial Advisor Meeting", # start_time="2025-10-22 14:00", # end_time="2025-10-22 15:00" # ) ``` -------------------------------- ### Define Module Imports for React Project Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/index.html Specifies the import paths for various React-related modules. This configuration helps in managing dependencies and ensuring correct module resolution, especially when using a module bundler or CDN services like esm.sh. It maps module names to their respective URLs. ```json { "imports": { "react/": "https://esm.sh/react@^19.1.1/", "react": "https://esm.sh/react@^19.1.1", "react-dom/": "https://esm.sh/react-dom@^19.1.1/", "react-router-dom": "https://esm.sh/react-router-dom@^7.8.0" } } ``` -------------------------------- ### Manage Subscriptions and Spending with Specialized Agents (Python) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This Python code orchestrates daily spending management by defining specialized sub-agents for subscriptions, discounts, and duplicate charge detection. It uses the PlanReActPlanner for task execution and integrates with a financial agent tool. The main DailySpendingsAgent coordinates these sub-agents to handle user requests related to subscriptions, discounts, and potential overcharges. ```python from google.adk.agents import Agent from google.adk.planners import PlanReActPlanner from google.adk.tools.agent_tool import AgentTool # Define specialized sub-agents subscriptions_agent = Agent( name="SubscriptionAgent", description="Manages user subscriptions", instruction="Identify subscriptions from recurring transactions", model="gemini-2.5-flash", tools=[cancel_spotify_subscription, human_approval, financial_agent_tool] ) discounts_agent = Agent( name="DiscountAgent", description="Finds relevant discounts and coupons", model="gemini-2.5-flash", instruction="Get user's partners and transactions to identify savings", tools=[financial_agent_tool] ) duplicate_charge_detection_agent = Agent( name="DuplicateChargeDetectionAgent", description="Detects potential duplicate charges", model="gemini-2.5-flash", instruction="Find transactions with same merchant, amount, and date", tools=[human_approval, financial_agent_tool] ) # Orchestrator for daily spending tasks daily_spendings_agent = Agent( name="daily_spendings_agent", model="gemini-2.5-flash", planner=PlanReActPlanner(), sub_agents=[ subscriptions_agent, discounts_agent, duplicate_charge_detection_agent ], description="Manages daily spending, subscriptions, discounts, and duplicate charges", tools=[financial_agent_tool] ) # Example usage scenarios: # User: "Can you check my subscriptions?" # User: "Are there any discounts available for me?" # User: "I think I was double-charged for something." ``` -------------------------------- ### Provide Market Data and Investment Info via Google Search (Python) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This code sets up an Investments Agent specialized in providing market data and financial information using Google Search. It defines a SearchAgent for financial queries and an AgentTool to use it. The InvestmentsAgent then uses this tool to answer questions about stock prices, company metrics, and financial concepts, always including a disclaimer and citing sources. ```python from google.adk.agents import Agent from google.adk.tools import google_search from google.adk.tools.agent_tool import AgentTool # Create search agent specialized for financial queries search_agent = Agent( model="gemini-2.5-flash", name="SearchAgent", instruction="You are a specialist in Google Search for financial information", tools=[google_search] ) search_tool = AgentTool(agent=search_agent) # Define the investments agent investments_agent = Agent( name="InvestmentsAgent", description="For helping users with investment information", model="gemini-2.5-flash", instruction=""" You are an expert Investment Information Specialist. Provide factual information but never give financial advice. Use google_search to: - Fetch real-time market data: "current price of Bitcoin" - Get company metrics: "Apple Inc. market capitalization" - Explain concepts: "what is an exchange traded fund ETF" - Summarize news: "summary of latest FOMC meeting results" Always include disclaimer: This is for informational purposes only. Cite sources when providing data. """, tools=[search_tool] ) # Example queries the agent can handle: # "What's the current price of Google stock?" # "Explain what a 401k is" # "What happened in the stock market today?" ``` -------------------------------- ### Web Audio API for Browser-based Audio Streaming Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt Implements browser-based audio recording and playback for voice interactions using the Web Audio API. It sets up audio worklets for both receiving agent voice responses and capturing user voice input. Dependencies include browser support for Web Audio API and `navigator.mediaDevices.getUserMedia`. The recorder captures PCM data, and the player consumes it. ```typescript // Audio player setup for receiving agent voice responses export async function startAudioPlayerWorklet(): Promise<[AudioWorkletNode, AudioContext]> { const audioContext = new AudioContext({ sampleRate: 24000 }); await audioContext.audioWorklet.addModule('/static/js/pcm-player-processor.js'); const playerNode = new AudioWorkletNode(audioContext, 'pcm-player-processor'); playerNode.connect(audioContext.destination); return [playerNode, audioContext]; } // Audio recorder setup for capturing user voice export async function startAudioRecorderWorklet( onAudioData: (pcm: ArrayBuffer) => void ): Promise<[AudioWorkletNode, AudioContext, MediaStream]> { const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1, sampleRate: 16000 } }); const audioContext = new AudioContext({ sampleRate: 16000 }); await audioContext.audioWorklet.addModule('/static/js/pcm-recorder-processor.js'); const recorderNode = new AudioWorkletNode(audioContext, 'pcm-recorder-processor'); const source = audioContext.createMediaStreamSource(stream); recorderNode.port.onmessage = (event) => { onAudioData(event.data); }; source.connect(recorderNode); recorderNode.connect(audioContext.destination); return [recorderNode, audioContext, stream]; } // Usage in RealtimeAgentClient class RealtimeAgentClient { private websocket: any; // Placeholder for WebSocket instance private audioPlayerNode: AudioWorkletNode | undefined; private audioRecorderNode: AudioWorkletNode | undefined; async connect(reconnect: boolean = false) { // Placeholder for connection logic console.log('Connecting...'); } async startAudio() { const [playerNode, playerCtx] = await startAudioPlayerWorklet(); const [recorderNode, recorderCtx, stream] = await startAudioRecorderWorklet( (pcm) => this.sendAudioPcm(pcm) ); this.audioPlayerNode = playerNode; this.audioRecorderNode = recorderNode; // Reconnect in audio mode await this.connect(true); } private sendAudioPcm(buffer: ArrayBuffer) { const base64 = this.arrayBufferToBase64(buffer); if (this.websocket && this.websocket.readyState === WebSocket.OPEN) { this.websocket.send(JSON.stringify({ mime_type: 'audio/pcm', data: base64 })); } else { console.error('WebSocket is not open. Cannot send audio data.'); } } // Helper method to convert ArrayBuffer to Base64 string private arrayBufferToBase64(buffer: ArrayBuffer): string { let binary = ''; const bytes = new Uint8Array(buffer); const len = bytes.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return window.btoa(binary); } } ``` -------------------------------- ### Configure Tailwind CSS Theme for Cymbal Bank Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/index.html Extends the default Tailwind CSS theme to include custom colors and screen sizes specific to the Cymbal Bank UI. This configuration is typically found in a tailwind.config.js file. It defines a palette of colors for different UI elements and adds an extra-small screen breakpoint. ```javascript tailwind.config = { theme: { extend: { colors: { 'cymbal-dark': '#111827', 'cymbal-deep-dark': '#0f172a', 'cymbal-light': '#f3f4f6', 'cymbal-accent': '#22d3ee', 'cymbal-accent-hover': '#06b6d4', 'cymbal-text-primary': '#e5e7eb', 'cymbal-text-secondary': '#9ca3af', 'cymbal-border': '#374151', }, screens: { 'xs': '475px', }, }, }, } ``` -------------------------------- ### FastAPI WebSocket Handler for Agent Session Management (Python) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This Python code sets up a FastAPI application to handle WebSocket communication for managing agent sessions. It supports bidirectional streaming of text and audio data between the frontend and the agent system. Dependencies include fastapi, uvicorn, and google.adk libraries. ```python from fastapi import FastAPI, WebSocket from fastapi.middleware.cors import CORSMiddleware from google.adk.runners import InMemoryRunner from google.adk.agents import LiveRequestQueue from google.adk.agents.run_config import RunConfig import json import asyncio app = FastAPI() # CORS middleware setup for handling cross-origin requests app.add_middleware( CORSMiddleware, allow_origins=["*"], # Allows all origins allow_credentials=True, allow_methods=["*"], # Allows all methods allow_headers=["*"], # Allows all headers ) # In-memory runner for agents runner = InMemoryRunner() @app.websocket("/ws/agent/{agent_name}/{session_id}") async def websocket_endpoint(websocket: WebSocket, agent_name: str, session_id: str): await websocket.accept() print(f"WebSocket connection accepted for agent: {agent_name}, session: {session_id}") # Initialize LiveRequestQueue for the session request_queue = LiveRequestQueue() # Configure run settings run_config = RunConfig(request_queue=request_queue) # Load and run the agent try: # Assuming agent_name maps to a runnable agent definition agent_instance = runner.get_agent(agent_name) if not agent_instance: await websocket.send_text(json.dumps({"error": f"Agent {agent_name} not found"})) await websocket.close() return # Start agent processing in a background task task = asyncio.create_task( runner.run_agent_session( agent_instance=agent_instance, run_config=run_config, session_id=session_id ) ) while True: # Receive data from WebSocket data = await websocket.receive_json() # Assuming JSON data print(f"Received from client: {data}") # Process received data and add to the request queue if "text" in data: request_queue.put_text(data["text"]) elif "audio_chunk" in data: # Example for audio streaming request_queue.put_audio(data["audio_chunk"]) else: await websocket.send_json({"error": "Unknown message format"}) # Send agent responses back to the client (this part needs more logic) # For simplicity, let's assume agent outputs are directly put into the queue # and we need a mechanism to read from it and send to websocket. # This example assumes a direct response mechanism for illustration. # A more robust solution would involve a separate task to read from # agent_instance.outputs and send to websocket. # Example of sending a placeholder response: # await websocket.send_json({"response": "Processing your request..."}) except Exception as e: print(f"Error in WebSocket handler: {e}") await websocket.send_text(json.dumps({"error": str(e)})) finally: print("WebSocket connection closed") await websocket.close() # Example of how to run this FastAPI app: # Save the code as main.py and run: uvicorn main:app --reload ``` -------------------------------- ### Big Spendings Agent for Financial Analysis (Python) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This Python agent analyzes financial affordability for large purchases and mortgage eligibility using the 28/36 rule. It integrates with other agents to gather financial data and provides recommendations. Dependencies include google.adk.agents, google.adk.planners, and google.adk.tools.agent_tool. ```python from google.adk.agents import Agent from google.adk.planners import PlanReActPlanner from google.adk.tools.agent_tool import AgentTool big_spendings_agent = Agent( name="big_spendings_agent", model="gemini-2.5-flash", planner=PlanReActPlanner(), tools=[financial_agent_tool], description="Determines affordability of large purchases and mortgage eligibility", instruction=""" Analyze user's financial health for large purchases by querying financial_agent for: - Financial summary (income, expenses) - Net worth (assets, liabilities) - Cash flow (monthly in/out) - Life goals and savings For affordability: - Check stable income - Calculate debt-to-income ratio - Verify emergency fund exists - Assess impact on life goals For mortgage eligibility (28/36 rule): - 28% rule: Max 28% of gross monthly income for housing payment - 36% rule: Max 36% of gross monthly income for total debt Provide recommendations with evidence. Suggest advisor consultation if needed. """ ) # Example queries: # User: "Can I afford a new car?" # Agent fetches: cashflow, debts, net worth # Agent analyzes: income stability, debt ratio, savings impact # Agent responds: "Based on your monthly income of $6,000 and current debts # of $800/month, you have $2,000 available after expenses..." # User: "Do I qualify for a mortgage?" # Agent calculates: 28% of $6,000 = $1,680 max housing payment # 36% of $6,000 = $2,160 max total debt # Agent responds: "You qualify for a mortgage with housing payment up to $1,680/month" ``` -------------------------------- ### Establish WebSocket Connection for Real-time Agent Communication Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This TypeScript code snippet demonstrates how to establish a persistent WebSocket connection to the agent backend using the RealtimeAgentClient. It includes handlers for connection events, text responses, and audio interactions. The client can be configured to connect in text or audio mode and disconnect when no longer needed. ```typescript import { RealtimeAgentClient } from './lib/wsAgent'; // Initialize client with event handlers const client = new RealtimeAgentClient({ onOpen: () => console.log('Connected to agent'), onClose: () => console.log('Disconnected'), onError: (e) => console.error('Connection error:', e), onText: (text) => console.log('Agent response:', text), onTurnComplete: () => console.log('Agent finished speaking'), onInterrupted: () => console.log('Agent interrupted'), onIsSpeaking: (speaking) => console.log('Is speaking:', speaking) }); // Connect in text mode await client.connect(false); // Send a message to the agent client.sendText('Show me my transaction history in a table format'); // Connect in audio mode for voice interactions await client.startAudio(); // Disconnect when done client.disconnect(); ``` -------------------------------- ### Root Agent Orchestration with Specialized Sub-Agents Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This Python code snippet defines the root agent for the Cymbal Bank Orchestra, acting as a request router. It utilizes Google's ADK `LlmAgent` and `AgentTool` to delegate tasks to specialized sub-agents like financial, calendar, and investment agents. The agent is configured with a model, name, description, and specific instructions for task delegation. ```python from google.adk.agents import LlmAgent from google.adk.tools.agent_tool import AgentTool # Create agent tools from specialized agents financial_agent_tool = AgentTool(agent=financial_agent) daily_spendings_agent_tool = AgentTool(agent=daily_spendings_agent) investments_agent_tool = AgentTool(agent=investments_agent) calendar_agent_tool = AgentTool(agent=calendar_agent) big_spendings_agent_tool = AgentTool(agent=big_spendings_agent) # Define the root orchestrator agent root_agent = LlmAgent( model="gemini-2.0-flash-live-001", name="router_agent", description="Financial services agent with access to remote financial data", instruction=""" You are a financial assistant that delegates tasks to specialized sub-agents: - financial_agent: Core banking operations (accounts, transactions, goals) - calendar_subagent: Appointment booking and management - big_spendings_agent: Large purchase analysis and mortgage eligibility - daily_spendings_agent: Subscriptions, discounts, duplicate charges - investments_agent: Market data, investment concepts, financial news Always return data in JSON format when users request table display. """, tools=[ financial_agent_tool, daily_spendings_agent_tool, investments_agent_tool, calendar_agent_tool, big_spendings_agent_tool ] ) ``` -------------------------------- ### React Permissions Context Management for User Data Access Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt Manages user permissions using React's context API. It allows components to access and update permission states, and generates a contextual string for agent requests based on granted permissions. Dependencies include React. No external libraries are strictly required for the core context logic. ```typescript import React, { createContext, useContext, useState } from 'react'; interface Permission { id: string; label: string; enabled: boolean; description?: string; } interface PermissionsContextType { permissions: Permission[]; updatePermission: (id: string, enabled: boolean) => void; getPermissionContext: () => string; hasCompletedOnboarding: boolean; completeOnboarding: () => void; } export const PermissionsContext = createContext(undefined); export const PermissionsProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [permissions, setPermissions] = useState([ { id: 'accounts', label: 'Account Information', enabled: false }, { id: 'transactions', label: 'Transaction History', enabled: false }, { id: 'goals', label: 'Financial Goals', enabled: false }, { id: 'investments', label: 'Investment Data', enabled: false }, { id: 'calendar', label: 'Calendar Access', enabled: false } ]); const [hasCompletedOnboarding, setHasCompletedOnboarding] = useState(false); const updatePermission = (id: string, enabled: boolean) => { setPermissions(prev => prev.map(p => p.id === id ? { ...p, enabled } : p) ); }; const getPermissionContext = () => { const enabled = permissions.filter(p => p.enabled).map(p => p.label); return `User has granted access to: ${enabled.join(', ')}. Only use data from these categories in your responses.`; }; const completeOnboarding = () => { setHasCompletedOnboarding(true); }; return ( {children} ); }; export const usePermissions = () => { const context = useContext(PermissionsContext); if (context === undefined) { throw new Error('usePermissions must be used within a PermissionsProvider'); } return context; }; // Usage in components function ChatComponent() { const { getPermissionContext } = usePermissions(); const sendMessage = (text: string) => { const contextualMessage = `${getPermissionContext()}\n\nUser message: ${text}`; // Assuming 'client' is an existing WebSocket or API client instance // client.sendText(contextualMessage); }; return ( ); } ``` -------------------------------- ### Handle WebSocket Connections for Real-time Agent Communication (FastAPI) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This asynchronous function defines a WebSocket endpoint ('/ws/{user_id}') for handling real-time communication between clients and financial agents. It accepts user ID, audio mode, and an optional agent ID. The function establishes a WebSocket connection, initiates an agent session, and sets up bidirectional message handling tasks using asyncio. It processes incoming text messages, routing them as text content or audio data to the agent. The connection remains active until disconnected or an error occurs. ```python @app.websocket("/ws/{user_id}") async def websocket_endpoint(websocket: WebSocket, user_id: str, is_audio: str, agent_id: str = None): """Handle WebSocket connection for real-time agent communication""" await websocket.accept() print(f"Client #{user_id} connected, audio mode: {is_audio}, agent_id: {agent_id}") # Start agent session live_events, live_request_queue = await start_agent_session( user_id, is_audio == "true", agent_id ) # Create bidirectional communication tasks agent_to_client_task = asyncio.create_task( agent_to_client_messaging(websocket, live_events) ) client_to_agent_task = asyncio.create_task( client_to_agent_messaging(websocket, live_request_queue) ) # Wait until disconnect or error tasks = [agent_to_client_task, client_to_agent_task] await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) live_request_queue.close() print(f"Client #{user_id} disconnected") ``` -------------------------------- ### WebSocket Endpoint for Agent Communication Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt Handles WebSocket connections for real-time bidirectional communication between a client and an AI agent. It supports both text and audio-based interactions. ```APIDOC ## WebSocket /ws/{user_id} ### Description Handles WebSocket connections for real-time agent communication. Clients can connect to this endpoint to send messages to and receive responses from AI agents. Supports text and audio modes. ### Method WEBSOCKET ### Endpoint `/ws/{user_id}` ### Parameters #### Path Parameters - **user_id** (string) - Required - The unique identifier for the user establishing the connection. #### Query Parameters - **is_audio** (string) - Required - A string indicating whether the connection is for audio ('true') or text ('false') mode. - **agent_id** (string) - Optional - The identifier for a specific agent to be used for the session. If not provided, a default agent is used. ### Request Example (No direct request body for WebSocket establishment, but messages follow a specific JSON format) ### Response #### Success Response (101 Switching Protocols) - The connection is upgraded to WebSocket. #### Response Example (Messages exchanged over WebSocket) ```json { "mime_type": "text/plain", "data": "Hello, agent!" } ``` ```json { "mime_type": "audio/pcm", "data": "BASE64_ENCODED_AUDIO_DATA" } ``` **Note:** Responses from the agent will follow a similar structure, indicating the content type and data. ``` -------------------------------- ### Connect to Remote Financial Service with A2A Protocol (Python) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This snippet demonstrates how to connect to a remote financial data service using the A2A protocol. It initializes a RemoteA2aAgent with a name, description, and agent card URL. The agent can then be used by other agents to perform banking operations like fetching transactions or net worth. ```python from google.adk.agents.remote_a2a_agent import RemoteA2aAgent # Create a remote agent that connects to the financial API financial_agent = RemoteA2aAgent( name="financial_agent", description="Agent with access to financial data and banking operations", agent_card="https://a2a-ep2-33wwy4ha3a-uw.a.run.app/.well-known/agent-card.json" ) # The agent can be called by other agents via AgentTool # Example usage in another agent's instruction: """ To get user transactions: { "tool_name": "get_transactions", "user_id": "user-001", "start_date": "2025-01-01", "end_date": "2025-10-21" } To get net worth: { "tool_name": "get_net_worth", "user_id": "user-001" } """ ``` -------------------------------- ### Root Agent - Main Request Router Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt The root agent orchestrates all user requests and delegates to specialized sub-agents based on the request type. ```APIDOC ## Root Agent - Main Request Router ### Description The root agent orchestrates all user requests and delegates to specialized sub-agents based on the request type. It acts as the main entry point for user interactions with the financial services platform. ### Method N/A (This describes an agent's internal logic and tools, not a direct HTTP endpoint) ### Endpoint N/A ### Parameters N/A ### Request Example ```python from google.adk.agents import LlmAgent from google.adk.tools.agent_tool import AgentTool # Assume specialized agents (financial_agent, daily_spendings_agent, etc.) are already initialized # Create agent tools from specialized agents financial_agent_tool = AgentTool(agent=financial_agent) daily_spendings_agent_tool = AgentTool(agent=daily_spendings_agent) investments_agent_tool = AgentTool(agent=investments_agent) calendar_agent_tool = AgentTool(agent=calendar_agent) big_spendings_agent_tool = AgentTool(agent=big_spendings_agent) # Define the root orchestrator agent root_agent = LlmAgent( model="gemini-2.0-flash-live-001", name="router_agent", description="Financial services agent with access to remote financial data", instruction=""" You are a financial assistant that delegates tasks to specialized sub-agents: - financial_agent: Core banking operations (accounts, transactions, goals) - calendar_subagent: Appointment booking and management - big_spendings_agent: Large purchase analysis and mortgage eligibility - daily_spendings_agent: Subscriptions, discounts, duplicate charges - investments_agent: Market data, investment concepts, financial news Always return data in JSON format when users request table display. """, tools=[ financial_agent_tool, daily_spendings_agent_tool, investments_agent_tool, calendar_agent_tool, big_spendings_agent_tool ] ) # Example of how a user request would be processed by this agent: # user_request = "What are my recent transactions?" # response = root_agent.invoke(user_request) ``` ### Response #### Success Response - **delegated_response** (object/string) - The response from the sub-agent that handled the request. #### Response Example ```json { "delegated_response": { "transactions": [ { "Transaction ID": "txn-001", "Account ID": "acc-user-001-checking", "Date": "2025-10-15", "Description": "Coffee Shop", "Amount": -4.50, "Category": "Food & Dining" } ] } } ``` ``` -------------------------------- ### WebSocket Connection - Real-time Agent Communication Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt Establishes a persistent WebSocket connection to the agent backend for streaming text and audio communication with AI agents. ```APIDOC ## WebSocket Connection - Real-time Agent Communication ### Description Establishes a persistent WebSocket connection to the agent backend for streaming text and audio communication with AI agents. ### Method WebSockets ### Endpoint ws://localhost:8000/ws/agent ### Parameters N/A ### Request Example ```typescript import { RealtimeAgentClient } from './lib/wsAgent'; // Initialize client with event handlers const client = new RealtimeAgentClient({ onOpen: () => console.log('Connected to agent'), onClose: () => console.log('Disconnected'), onError: (e) => console.error('Connection error:', e), onText: (text) => console.log('Agent response:', text), onTurnComplete: () => console.log('Agent finished speaking'), onInterrupted: () => console.log('Agent interrupted'), onIsSpeaking: (speaking) => console.log('Is speaking:', speaking) }); // Connect in text mode await client.connect(false); // Send a message to the agent client.sendText('Show me my transaction history in a table format'); // Connect in audio mode for voice interactions await client.startAudio(); // Disconnect when done client.disconnect(); ``` ### Response #### Success Response (WebSocket Connection Established) - **Connection Status** (string) - Indicates successful connection. #### Response Example ``` Connected to agent ``` #### Text Response Example ``` Agent response: Here is your transaction history... ``` ``` -------------------------------- ### Route Client Messages to Agent (WebSocket) Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This asynchronous function is responsible for receiving messages from a WebSocket client and forwarding them to the appropriate agent via a live request queue. It handles both plain text and base64-encoded audio (PCM) data. Text messages are converted into 'user' role content, while audio data is decoded and sent as real-time blobs. This function runs in a loop, continuously processing incoming messages until the WebSocket connection is closed or an error occurs. ```python async def client_to_agent_messaging(websocket, live_request_queue): """Route client messages to agent""" while True: message = json.loads(await websocket.receive_text()) mime_type = message["mime_type"] data = message["data"] if mime_type == "text/plain": content = Content(role="user", parts=[Part.from_text(text=data)]) live_request_queue.send_content(content=content) elif mime_type == "audio/pcm": decoded_data = base64.b64decode(data) live_request_queue.send_realtime(Blob(data=decoded_data, mime_type=mime_type)) ``` -------------------------------- ### Enable CORS Middleware in FastAPI Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt This snippet configures Cross-Origin Resource Sharing (CORS) middleware for a FastAPI application. It allows requests from a specific frontend origin ('http://localhost:5173'), credentials, and any HTTP methods or headers. This is crucial for enabling communication between the backend and a frontend running on a different port or domain. ```python app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:5173"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"] ) ``` -------------------------------- ### Transaction History API - Retrieve User Financial Data Source: https://context7.com/marcus990/cymbal-bank-orchestra/llms.txt FastAPI endpoint that retrieves transaction history for a specific user by delegating to the transaction history agent. ```APIDOC ## Transaction History API - Retrieve User Financial Data ### Description FastAPI endpoint that retrieves transaction history for a specific user by delegating to the transaction history agent. ### Method GET ### Endpoint `/api/transaction-history/{user_id}` ### Parameters #### Path Parameters - **user_id** (string) - Required - The ID of the user whose transaction history is to be retrieved. #### Query Parameters N/A #### Request Body N/A ### Request Example ```python import requests response = requests.get( 'http://localhost:8001/api/transaction-history/user-001', headers={'Content-Type': 'application/json'} ) ``` ### Response #### Success Response (200) - **transactions** (array) - A list of transaction objects. - **Transaction ID** (string) - Unique identifier for the transaction. - **Account ID** (string) - Identifier for the account the transaction occurred on. - **Date** (string) - The date of the transaction (YYYY-MM-DD). - **Description** (string) - A description of the transaction. - **Amount** (number) - The amount of the transaction. Negative for expenses, positive for income. - **Category** (string) - The category of the transaction. #### Response Example ```json [ { "Transaction ID": "txn-001", "Account ID": "acc-user-001-checking", "Date": "2025-10-15", "Description": "Coffee Shop", "Amount": -4.50, "Category": "Food & Dining" } ] ``` #### Error Response (404 or other) - **error** (object) - Contains error details. - **message** (string) - A message describing the error. #### Error Response Example ```json { "error": { "message": "User not found or no transactions available." } } ``` ``` -------------------------------- ### Spending Analysis JSON Data Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/docs/JSON_TABLE_INTEGRATION.md This JSON snippet represents a monthly spending breakdown, including budgeted and actual spending for each month. It's used to demonstrate table rendering capabilities and provides a structured view of financial data. ```json [ {"month": "January", "spending": 1200.50, "budget": 1500.00}, {"month": "February", "spending": 980.25, "budget": 1500.00} ] ``` -------------------------------- ### TypeScript State Management for JSON Data Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/docs/JSON_TABLE_INTEGRATION.md Defines the TypeScript interface for storing detected JSON data, including a unique identifier, the parsed JSON content, and a timestamp. It also shows the initialization of this state using the useState hook in React. ```typescript interface JsonData { id: string; // Unique identifier data: any; // Parsed JSON content timestamp: Date; // When detected } const [jsonData, setJsonData] = useState([]); ``` -------------------------------- ### React Table Rendering for JSON Data Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/docs/JSON_TABLE_INTEGRATION.md Illustrates a React function responsible for rendering detected JSON data into a user-friendly table format. It handles both array and object types, with specific logic for displaying arrays as index-value pairs and objects as key-value pairs. Nested data is displayed as formatted JSON. ```javascript const renderJsonTable = (data: any): React.JSX.Element => { if (Array.isArray(data)) { // Render array as index-value table } else if (typeof data === 'object') { // Render object as key-value table } }; ``` -------------------------------- ### JavaScript JSON Detection and Extraction Logic Source: https://github.com/marcus990/cymbal-bank-orchestra/blob/main/frontend/docs/JSON_TABLE_INTEGRATION.md Provides a JavaScript function designed to detect and extract JSON patterns (objects and arrays) from a given text string. It uses regular expressions for matching and includes a placeholder for parsing and validation logic. The function aims to return only meaningful JSON structures. ```javascript const detectAndExtractJson = (text: string): any[] => { const jsonPatterns = [ /\{[\s\S]*?\}/g, // Non-greedy object matching /\[[\s\S]*?\]/g // Non-greedy array matching ]; // Parse and validate each match // Return meaningful JSON structures only }; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.