mirror of https://github.com/kortix-ai/suna.git
222 lines
6.6 KiB
TypeScript
222 lines
6.6 KiB
TypeScript
import { useTheme } from '@/hooks/useThemeColor';
|
|
import { ParsedToolCall } from '@/utils/message-parser';
|
|
import React from 'react';
|
|
import { StyleSheet, View } from 'react-native';
|
|
import { Body, Caption } from '../Typography';
|
|
import { AskToolView } from './AskToolView';
|
|
|
|
// Generic tool view for unknown tools
|
|
export const GenericToolView: React.FC<{ toolCall: ParsedToolCall }> = ({ toolCall }) => {
|
|
const theme = useTheme();
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
padding: 16,
|
|
backgroundColor: theme.muted + '20',
|
|
borderRadius: 8,
|
|
marginBottom: 12,
|
|
},
|
|
name: {
|
|
color: theme.foreground,
|
|
fontWeight: '600',
|
|
marginBottom: 8,
|
|
},
|
|
param: {
|
|
color: theme.mutedForeground,
|
|
marginBottom: 4,
|
|
},
|
|
value: {
|
|
color: theme.foreground,
|
|
fontFamily: 'monospace',
|
|
fontSize: 12,
|
|
},
|
|
});
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<Body style={styles.name}>{toolCall.functionName}</Body>
|
|
{Object.entries(toolCall.parameters).map(([key, value]) => (
|
|
<View key={key}>
|
|
<Caption style={styles.param}>{key}:</Caption>
|
|
<Body style={styles.value}>{String(value)}</Body>
|
|
</View>
|
|
))}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
// File operation tool view
|
|
export const FileToolView: React.FC<{ toolCall: ParsedToolCall }> = ({ toolCall }) => {
|
|
const theme = useTheme();
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
padding: 16,
|
|
backgroundColor: theme.muted + '20',
|
|
borderRadius: 8,
|
|
marginBottom: 12,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 12,
|
|
},
|
|
icon: {
|
|
width: 24,
|
|
height: 24,
|
|
borderRadius: 4,
|
|
backgroundColor: theme.primary + '20',
|
|
marginRight: 8,
|
|
},
|
|
name: {
|
|
color: theme.foreground,
|
|
fontWeight: '600',
|
|
},
|
|
filePath: {
|
|
color: theme.primary,
|
|
fontFamily: 'monospace',
|
|
fontSize: 12,
|
|
marginBottom: 8,
|
|
},
|
|
content: {
|
|
color: theme.mutedForeground,
|
|
fontSize: 12,
|
|
fontFamily: 'monospace',
|
|
maxHeight: 200,
|
|
},
|
|
});
|
|
|
|
const filePath = toolCall.parameters.file_path || toolCall.parameters.path;
|
|
const content = toolCall.parameters.file_contents || toolCall.parameters.content;
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<View style={styles.header}>
|
|
<View style={styles.icon} />
|
|
<Body style={styles.name}>{toolCall.functionName.replace(/-/g, ' ')}</Body>
|
|
</View>
|
|
{filePath && <Body style={styles.filePath}>{filePath}</Body>}
|
|
{content && <Body style={styles.content}>{String(content).substring(0, 500)}</Body>}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
// Command execution tool view
|
|
export const CommandToolView: React.FC<{ toolCall: ParsedToolCall }> = ({ toolCall }) => {
|
|
const theme = useTheme();
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
padding: 16,
|
|
backgroundColor: theme.muted + '20',
|
|
borderRadius: 8,
|
|
marginBottom: 12,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 12,
|
|
},
|
|
icon: {
|
|
width: 24,
|
|
height: 24,
|
|
borderRadius: 4,
|
|
backgroundColor: theme.destructive + '20',
|
|
marginRight: 8,
|
|
},
|
|
name: {
|
|
color: theme.foreground,
|
|
fontWeight: '600',
|
|
},
|
|
command: {
|
|
color: theme.foreground,
|
|
fontFamily: 'monospace',
|
|
fontSize: 12,
|
|
backgroundColor: theme.muted + '40',
|
|
padding: 8,
|
|
borderRadius: 4,
|
|
},
|
|
});
|
|
|
|
const command = toolCall.parameters.command;
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<View style={styles.header}>
|
|
<View style={styles.icon} />
|
|
<Body style={styles.name}>Execute Command</Body>
|
|
</View>
|
|
{command && <Body style={styles.command}>{String(command)}</Body>}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
// Web search tool view
|
|
export const WebSearchToolView: React.FC<{ toolCall: ParsedToolCall }> = ({ toolCall }) => {
|
|
const theme = useTheme();
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
padding: 16,
|
|
backgroundColor: theme.muted + '20',
|
|
borderRadius: 8,
|
|
marginBottom: 12,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 12,
|
|
},
|
|
icon: {
|
|
width: 24,
|
|
height: 24,
|
|
borderRadius: 4,
|
|
backgroundColor: theme.accent + '20',
|
|
marginRight: 8,
|
|
},
|
|
name: {
|
|
color: theme.foreground,
|
|
fontWeight: '600',
|
|
},
|
|
query: {
|
|
color: theme.foreground,
|
|
fontStyle: 'italic',
|
|
marginBottom: 8,
|
|
},
|
|
});
|
|
|
|
const query = toolCall.parameters.query || toolCall.parameters.search_query;
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<View style={styles.header}>
|
|
<View style={styles.icon} />
|
|
<Body style={styles.name}>Web Search</Body>
|
|
</View>
|
|
{query && <Body style={styles.query}>"{String(query)}"</Body>}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
// Ask tool view wrapper to match the registry interface
|
|
const AskToolViewWrapper: React.FC<{ toolCall: ParsedToolCall }> = ({ toolCall }) => {
|
|
return <AskToolView toolCall={toolCall} />;
|
|
};
|
|
|
|
// Tool registry - maps tool names to their view components
|
|
export const TOOL_VIEW_REGISTRY: Record<string, React.FC<{ toolCall: ParsedToolCall }>> = {
|
|
'create-file': FileToolView,
|
|
'delete-file': FileToolView,
|
|
'str-replace': FileToolView,
|
|
'full-file-rewrite': FileToolView,
|
|
'execute-command': CommandToolView,
|
|
'web-search': WebSearchToolView,
|
|
'crawl-webpage': WebSearchToolView,
|
|
'ask': AskToolViewWrapper,
|
|
};
|
|
|
|
// Main tool view component that uses the registry
|
|
export const ToolView: React.FC<{ toolCall: ParsedToolCall }> = ({ toolCall }) => {
|
|
const ViewComponent = TOOL_VIEW_REGISTRY[toolCall.functionName] || GenericToolView;
|
|
return <ViewComponent toolCall={toolCall} />;
|
|
};
|