Overview
Workspace Context Integration enables ambient intelligence by automatically detecting and syncing the user’s current work environment to agent systems. This allows AI agents to provide contextually relevant suggestions, smart defaults, and page-aware assistance without requiring explicit user input.
Unlike user-initiated interactions, workspace context operates passively in the background, continuously monitoring the application state and making it available to both frontend and backend agent systems.
What is Ambient Intelligence?
Ambient intelligence means the system understands:
Where you are : Current page, active view, focused artifact
What you’re working on : Selected portfolio, date range, active workbook
What you can do : Available actions based on current context
Your preferences : User settings that affect agent behavior
This contextual awareness enables agents to offer proactive insights, pre-fill requests with relevant data, and filter tool availability based on the current page.
Key Benefits
Smart Defaults Automatically pre-fill agent requests with portfolio ID, date, or workbook context
Page-Aware Tools Show only relevant actions based on current view (spreadsheet vs dashboard)
Proactive Insights Agent suggests contextually relevant actions without being asked
Reduced Friction Users don’t need to repeatedly specify context in every request
Architecture
Context Flow Diagram
Automatic Context Detection
The WorkspaceProvider automatically detects context from:
URL Parameters : Extracts IDs from route segments
Page State : Monitors active components and focused elements
Local Storage : Retrieves persisted user selections
Props & Events : Listens to component state changes
State Management Flow
// Automatic detection in WorkspaceProvider
useEffect (() => {
const detected = {
currentView: detectViewFromRoute ( pathname ),
workbookId: extractFromUrl ( 'workbookId' ),
selectedPortfolioId: getUserSelection ( 'portfolio' ),
selectedDate: getActiveDate (),
availableActions: getActionsForView ( currentView ),
};
setContext ( detected );
syncToBackend ( detected );
}, [ pathname , pageState ]);
Context Types
Core Context Fields
View Context currentView - Current page/feature (workbook, dashboard, workflow)focusMode - User’s focus area within the view
Artifact Context workbookId - Active spreadsheet identifierdashboardId - Active dashboard identifierworkflowId - Active workflow identifier
Selection Context selectedPortfolioId - Currently selected portfolioselectedDate - Currently selected dateselectedDateRange - Date range selection
Action Context availableActions - Actions available in current viewrecentActions - Recently performed actions
Context Schema
interface WorkspaceContext {
// View Context
currentView : 'workspace' | 'workbook' | 'dashboard' | 'workflow' | 'catalog' | 'validation' | 'visual_query_builder' | 'unknown' ;
focusMode ?: 'spreadsheet' | 'dashboard' | 'workflow' | 'validation' | 'pipeline' | 'catalog' ;
// Artifact Context
workbookId ?: string ;
workbookName ?: string ;
dashboardId ?: string ;
dashboardName ?: string ;
workflowId ?: string ;
workflowName ?: string ;
widgetId ?: string ;
// Selection Context
selectedPortfolioId ?: string ;
selectedPortfolioName ?: string ;
selectedDate ?: string ; // ISO 8601
selectedDateRange ?: {
start : string ;
end : string ;
};
// Action Context
availableActions ?: string [];
// Session Context
sessionId ?: string ;
userId ?: string ;
organizationId ?: string ;
teamId ?: string ;
}
Backend Setup
Next.js Route
Python Backend
// lib/middleware/workspace-context.ts
import { NextRequest } from 'next/server' ;
import { WorkspaceContextSchema } from '@/lib/validation/workspace-context-schema' ;
export async function extractWorkspaceContext ( request : NextRequest ) {
try {
// Try request body first
const body = await request . json ();
if ( body . workspace ) {
return WorkspaceContextSchema . parse ( body . workspace );
}
// Fallback to headers
const headerValue = request . headers . get ( 'X-Workspace-Context' );
if ( headerValue ) {
const parsed = JSON . parse ( headerValue );
return WorkspaceContextSchema . parse ( parsed );
}
} catch ( error ) {
console . warn ( 'Failed to extract workspace context:' , error );
}
return null ;
}
// Usage in API route
export async function POST ( request : NextRequest ) {
const workspace = await extractWorkspaceContext ( request );
const response = await fetch ( AGENT_BACKEND_URL , {
method: 'POST' ,
headers: {
'X-Workspace-Context' : JSON . stringify ( workspace ),
},
body: JSON . stringify ({ ... data , workspace }),
});
return response ;
}
Forward Context to Backend
// lib/agent/workspace-sync.ts
import { buildAgentUrl } from '@/lib/config/agent-backend-url' ;
import { getAuthHeaders } from '@/lib/api/backend-auth' ;
export async function syncWorkspaceContext ( context : WorkspaceContext ) {
const authHeaders = await getAuthHeaders ();
const url = buildAgentUrl ( '/api/workspace/sync' );
await fetch ( url , {
method: 'POST' ,
headers: {
... authHeaders ,
'Content-Type' : 'application/json' ,
'X-Workspace-Context' : JSON . stringify ( context ),
},
body: JSON . stringify ( context ),
});
}
Frontend Implementation
WorkspaceProvider Setup
// lib/contexts/WorkspaceContext.tsx
import { createContext , useContext , useEffect , useState } from 'react' ;
import { usePathname } from 'next/navigation' ;
import { syncWorkspaceContext } from '@/lib/agent/workspace-sync' ;
import type { WorkspaceContext } from '@/lib/types/workspace' ;
const WorkspaceContext = createContext < WorkspaceContext | null >( null );
export function WorkspaceProvider ({ children } : { children : React . ReactNode }) {
const pathname = usePathname ();
const [ context , setContext ] = useState < WorkspaceContext >({
currentView: 'unknown' ,
availableActions: [],
});
useEffect (() => {
// Auto-detect context from URL and page state
const detected = detectContext ( pathname );
setContext ( detected );
// Sync to backend
syncWorkspaceContext ( detected );
}, [ pathname ]);
return (
< WorkspaceContext . Provider value = { context } >
{ children }
</ WorkspaceContext . Provider >
);
}
export function useWorkspaceContext () {
const context = useContext ( WorkspaceContext );
if ( ! context ) {
throw new Error ( 'useWorkspaceContext must be used within WorkspaceProvider' );
}
return context ;
}
Context Detection Logic
// lib/utils/context-detection.ts
import type { WorkspaceContext } from '@/lib/types/workspace' ;
export function detectContext ( pathname : string ) : WorkspaceContext {
const segments = pathname . split ( '/' ). filter ( Boolean );
// Detect view from route
const currentView = detectViewFromRoute ( segments );
// Extract IDs from URL
const workbookId = extractIdFromSegments ( segments , 'workbooks' );
const dashboardId = extractIdFromSegments ( segments , 'dashboards' );
const workflowId = extractIdFromSegments ( segments , 'workflows' );
// Determine available actions
const availableActions = getActionsForView ( currentView );
return {
currentView ,
workbookId ,
dashboardId ,
workflowId ,
availableActions ,
};
}
function detectViewFromRoute ( segments : string []) : WorkspaceContext [ 'currentView' ] {
if ( segments . includes ( 'workbooks' )) return 'workbook' ;
if ( segments . includes ( 'dashboards' )) return 'dashboard' ;
if ( segments . includes ( 'workflows' )) return 'workflow' ;
if ( segments . includes ( 'catalog' )) return 'catalog' ;
if ( segments . includes ( 'validation' )) return 'validation' ;
if ( segments . includes ( 'data-modeling' )) return 'visual_query_builder' ;
return 'workspace' ;
}
function getActionsForView ( view : string ) : string [] {
const actionMap : Record < string , string []> = {
workbook: [ 'update_spreadsheet' , 'create_formula' , 'insert_data' ],
dashboard: [ 'create_widget' , 'update_chart' , 'refresh_data' ],
workflow: [ 'create_workflow' , 'update_workflow' , 'test_workflow' ],
validation: [ 'create_rule' , 'run_validation' , 'view_breaches' ],
};
return actionMap [ view ] || [];
}
Custom Hook for Components
// lib/hooks/use-agent-context.ts
import { useWorkspaceContext } from '@/lib/contexts/WorkspaceContext' ;
export function useAgentContext () {
const workspace = useWorkspaceContext ();
const sendAgentRequest = async ( message : string ) => {
const response = await fetch ( '/api/agent' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
messages: [{ role: 'user' , content: message }],
workspace , // ← Automatically include context
}),
});
return response . json ();
};
return {
... workspace ,
sendAgentRequest ,
};
}
Complete Example
Page-Specific Agent Suggestions
Workbook Page
Backend Tool
// app/workbooks/[id]/page.tsx
import { useAgentContext } from '@/lib/hooks/use-agent-context' ;
import { useEffect , useState } from 'react' ;
export default function WorkbookPage ({ params } : { params : { id : string } }) {
const { currentView , workbookId , sendAgentRequest } = useAgentContext ();
const [ suggestions , setSuggestions ] = useState ([]);
useEffect (() => {
// Context automatically includes workbookId
// Agent knows we're in a spreadsheet context
async function fetchSuggestions () {
const response = await sendAgentRequest ( 'Give me suggestions' );
setSuggestions ( response . suggestions );
}
fetchSuggestions ();
}, [ workbookId ]);
return (
< div >
< h1 > Workbook { workbookId } </ h1 >
< AgentSuggestions items = { suggestions } />
< SpreadsheetGrid />
</ div >
);
}
Context Detection
Automatic Detection
The WorkspaceProvider automatically detects context changes through:
Monitors Next.js usePathname() hook to detect navigation useEffect (() => {
const newContext = detectContext ( pathname );
setContext ( newContext );
}, [ pathname ]);
Listens to component state changes via props useEffect (() => {
updateContext ({
selectedPortfolioId: portfolio . id ,
selectedPortfolioName: portfolio . name ,
});
}, [ portfolio ]);
Detects user selections and updates context const handlePortfolioSelect = ( portfolio ) => {
updateContext ({
selectedPortfolioId: portfolio . id ,
});
};
Manual Context Override
In some cases, you may want to manually set context:
import { useWorkspaceContext } from '@/lib/contexts/WorkspaceContext' ;
function MyComponent () {
const { updateContext } = useWorkspaceContext ();
const handleCustomAction = () => {
// Manually update context
updateContext ({
focusMode: 'validation' ,
availableActions: [ 'run_validation' , 'view_results' ],
});
};
}
Context-Based Tool Filtering
Tools can declare their required context to control availability:
Smart Defaults
Pre-filling Agent Requests
Context enables automatic pre-filling of common parameters:
Python Tool
TypeScript Hook
@tool ( "query_portfolio_holdings" )
def query_portfolio_holdings (
portfolio_id : Optional[ str ] = None ,
date : Optional[ str ] = None ,
config : Optional[RunnableConfig] = None
) -> List[Dict]:
"""
Query portfolio holdings.
SMART DEFAULTS:
- portfolio_id: Uses selected portfolio if not specified
- date: Uses selected date if not specified
"""
workspace_context = extract_workspace_context(config)
# Smart default: Use selected portfolio
if not portfolio_id and workspace_context:
portfolio_id = workspace_context.selected_portfolio_id
if portfolio_id:
logger.info( f "Auto-detected portfolio: { workspace_context.selected_portfolio_name } " )
# Smart default: Use selected date
if not date and workspace_context:
date = workspace_context.selected_date
if date:
logger.info( f "Auto-detected date: { date } " )
# Validate required params
if not portfolio_id:
return {
"error" : "Portfolio ID required" ,
"suggestion" : "Select a portfolio or specify portfolio_id parameter"
}
# Execute query with smart defaults...
Best Practices
Context Hygiene
DO : Clear context when navigating away from artifacts
useEffect (() => {
return () => {
// Cleanup on unmount
updateContext ({
workbookId: undefined ,
dashboardId: undefined ,
});
};
}, []);
DON’T : Let stale context persist across unrelated pages
// BAD: Context from previous page leaks into new page
// Workbook ID still set after navigating to dashboard
DO : Debounce context updates for rapid changes
import { useDebouncedCallback } from 'use-debounce' ;
const debouncedSync = useDebouncedCallback (
( context ) => syncWorkspaceContext ( context ),
500 // Wait 500ms after last change
);
useEffect (() => {
debouncedSync ( context );
}, [ context ]);
DO : Only sync context when it actually changes
const prevContextRef = useRef < WorkspaceContext >();
useEffect (() => {
// Deep comparison to avoid unnecessary syncs
if ( ! isEqual ( prevContextRef . current , context )) {
syncWorkspaceContext ( context );
prevContextRef . current = context ;
}
}, [ context ]);
Security Considerations
DO : Validate context permissions on backend
def validate_context_permissions (
workspace_context : WorkspaceContext,
user_id : str
) -> bool :
"""Ensure user has access to context artifacts"""
if workspace_context.workbook_id:
if not user_has_workbook_access(user_id, workspace_context.workbook_id):
raise PermissionError ( "User cannot access this workbook" )
if workspace_context.selected_portfolio_id:
if not user_has_portfolio_access(user_id, workspace_context.selected_portfolio_id):
raise PermissionError ( "User cannot access this portfolio" )
return True
DON’T : Trust frontend context without validation
Troubleshooting
Context Not Detected
Symptoms : Agent doesn’t have access to current page context
Solutions :
Check WorkspaceProvider
Ensure your component is wrapped in <WorkspaceProvider> // In app/layout.tsx
< WorkspaceProvider >
{ children }
</ WorkspaceProvider >
Verify Detection Logic
Add debug logging to context detection useEffect (() => {
console . log ( 'Current pathname:' , pathname );
console . log ( 'Detected context:' , context );
}, [ pathname , context ]);
Check Sync Status
Verify context is being sent to backend // In workspace-sync.ts
console . log ( 'Syncing context:' , context );
Context Not Reaching Backend
Symptoms : Backend tools don’t receive workspace context
Solutions :
Verify Headers
Check that X-Workspace-Context header is set // In API route
console . log ( 'Request headers:' , request . headers . get ( 'X-Workspace-Context' ));
Check Request Body
Ensure context is in request body if not using headers # In Python backend
print ( f "Request body workspace: { data.workspace } " )
Validate Schema
Ensure context matches expected schema try :
workspace_context = WorkspaceContext( ** workspace_data)
print ( f "Valid context: { workspace_context } " )
except Exception as e:
print ( f "Invalid context: { e } " )
Stale Context
Symptoms : Context from previous page persists on new page
Solutions :
Add cleanup in useEffect return function
Implement deep comparison to detect actual changes
Clear artifact-specific context on navigation
Implementation Status : Phase 1 & 2 Complete
Last Updated : 2025-10-29