Tool Context
Overview
The Tool Context provides a simple React context for sharing tool configurations across the application. It serves as a lightweight state management solution for tool-related data that needs to be accessed by multiple components.
Location: src/contexts/ToolContext.tsx
Dependencies: React Context API
Lines of Code: ~26
Purpose
The ToolContext enables:
- Centralized tool configuration storage
- Cross-component access to tool settings
- Integration point for tool-related state management
Interface Definition
interface ToolContextType {
toolConfigs: Record<string, Record<string, any>>;
}
Implementation
Context Creation
const ToolContext = createContext<ToolContextType>({
toolConfigs: {},
});
Provider Component
export function ToolProvider({
children,
toolConfigs
}: {
children: React.ReactNode;
toolConfigs: Record<string, Record<string, any>>;
}) {
return (
<ToolContext.Provider value=>
{children}
</ToolContext.Provider>
);
}
Hook for Consumption
export const useToolContext = () => useContext(ToolContext);
Usage Examples
Provider Setup
function App() {
const [toolConfigs, setToolConfigs] = useState({
'vertex_search': {
'datastore_id': 'aitana_public_welcome',
'no-stream': false
},
'file-browser': {
'bucketUrl': 'aitana-public-bucket',
'rootPath': '/'
}
});
return (
<ToolProvider toolConfigs={toolConfigs}>
<AssistantInterface />
</ToolProvider>
);
}
Context Consumption
function ToolStatusDisplay() {
const { toolConfigs } = useToolContext();
return (
<div>
{Object.entries(toolConfigs).map(([toolId, config]) => (
<div key={toolId}>
<h3>{toolId}</h3>
<pre>{JSON.stringify(config, null, 2)}</pre>
</div>
))}
</div>
);
}
Integration with Tool Components
function CustomToolComponent() {
const { toolConfigs } = useToolContext();
const myToolConfig = toolConfigs['my-tool'] || {};
// Use tool configuration in component logic
const enabled = myToolConfig.enabled !== false;
const apiKey = myToolConfig.apiKey;
return (
<div>
Status: {enabled ? 'Enabled' : 'Disabled'}
{/* Component implementation */}
</div>
);
}
Integration Points
Related Components
The ToolContext integrates with:
- ToolSelector Component
- Provides tool configurations to context
- Updates context when configurations change
- ToolConfigurator Component
- Reads current configurations from context
- Updates context with new configurations
- Assistant Components
- Access tool configurations for API calls
- Use configurations to modify behavior
Backend Integration
Tool configurations from the context are typically sent to the backend:
// Example API call using tool configurations
const { toolConfigs } = useToolContext();
const response = await fetch('/api/assistant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: userMessage,
tools_to_use: selectedTools,
toolConfigs: toolConfigs
})
});
State Management Pattern
Simple State Flow
User Interaction → ToolSelector → ToolContext → Components
↓
ToolConfigurator → ToolContext → API Calls
Configuration Updates
// Typical pattern for updating tool configurations
function updateToolConfig(toolId: string, newConfig: Record<string, any>) {
setToolConfigs(prev => ({
...prev,
[toolId]: {
...prev[toolId],
...newConfig
}
}));
}
Limitations
Simple Design
- Read-only in context: Context provides configurations but doesn’t handle updates
- No validation: Context doesn’t validate configuration data
- No persistence: Context doesn’t handle saving/loading configurations
Usage Recommendations
Use ToolContext for:
- Reading tool configurations across components
- Providing configurations to API calls
- Simple state sharing
Don’t use ToolContext for:
- Complex state management (use Redux or Zustand instead)
- Configuration validation (handle in components)
- Persistent storage (use localStorage or backend)
Alternative Approaches
Local State Management
For simple use cases, local state might be sufficient:
function AssistantPage() {
const [toolConfigs, setToolConfigs] = useState({});
return (
<div>
<ToolSelector
toolConfigs={toolConfigs}
onConfigChange={(toolId, config) => {
setToolConfigs(prev => ({ ...prev, [toolId]: config }));
}}
/>
<ChatInterface toolConfigs={toolConfigs} />
</div>
);
}
Global State Management
For complex applications, consider more robust solutions:
// Using Zustand or Redux
const useToolStore = create((set) => ({
toolConfigs: {},
updateToolConfig: (toolId, config) =>
set((state) => ({
toolConfigs: { ...state.toolConfigs, [toolId]: config }
}))
}));
Testing
Context Testing
import { render } from '@testing-library/react';
import { ToolProvider, useToolContext } from './ToolContext';
describe('ToolContext', () => {
it('provides tool configurations to children', () => {
const testConfigs = {
'test-tool': { enabled: true }
};
function TestComponent() {
const { toolConfigs } = useToolContext();
return <div data-testid="config">{JSON.stringify(toolConfigs)}</div>;
}
const { getByTestId } = render(
<ToolProvider toolConfigs={testConfigs}>
<TestComponent />
</ToolProvider>
);
expect(getByTestId('config')).toHaveTextContent('{"test-tool":{"enabled":true}}');
});
});
Related Documentation
- ToolSelector Component - Main tool selection interface
- ToolConfigurator Component - Individual tool configuration
- Tool Orchestrator System - Backend tool execution
API Reference
Types
interface ToolContextType {
toolConfigs: Record<string, Record<string, any>>;
}
Provider Props
| Prop | Type | Required | Description |
|---|---|---|---|
children |
React.ReactNode |
Yes | Child components to wrap |
toolConfigs |
Record<string, Record<string, any>> |
Yes | Tool configuration objects |
Hook Return Value
| Property | Type | Description |
|---|---|---|
toolConfigs |
Record<string, Record<string, any>> |
Current tool configurations |
File Structure
src/contexts/
└── ToolContext.tsx # Context implementation (26 lines)
src/components/tools/
├── ToolSelector.tsx # Uses context for configurations
└── ToolConfigurator.tsx # Updates context via callbacks