File size: 4,833 Bytes
bdbcdab
 
 
 
 
 
 
 
 
 
 
da5e0c7
7ead77c
da5e0c7
bdbcdab
 
 
 
 
472f63c
bdbcdab
 
8d40f7c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bdbcdab
 
 
 
7ead77c
8d40f7c
 
 
7ead77c
 
 
 
 
 
bdbcdab
1a390ae
bdbcdab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1a390ae
bdbcdab
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { Box, Typography } from '@mui/material';
import { keyframes } from '@mui/system';
import { useAgentStore, type ActivityStatus } from '@/store/agentStore';

const shimmer = keyframes`
  0% { background-position: -100% center; }
  50% { background-position: 200% center; }
  100% { background-position: -100% center; }
`;

const TOOL_LABELS: Record<string, string> = {
  sandbox_create: 'Creating sandbox for code development, this might take 1-2 minutes',
  bash: 'Running command in sandbox',
  hf_jobs: 'Running a GPU job, this might take a while',
  hf_repo_files: 'Uploading file',
  hf_repo_git: 'Git operation',
  hf_inspect_dataset: 'Inspecting dataset',
  hf_search: 'Searching',
  plan_tool: 'Planning',
  research: 'Researching',
};

/** Format raw research log into a clean status label. */
function formatResearchStatus(raw: string): string {
  const s = raw.replace(/^▸\s*/, '');
  const jsonStart = s.indexOf('{');
  const toolName = jsonStart > 0 ? s.slice(0, jsonStart).trim() : s.trim();
  let args: Record<string, string> = {};
  if (jsonStart > 0) {
    const jsonStr = s.slice(jsonStart);
    try {
      const parsed = JSON.parse(jsonStr);
      for (const [k, v] of Object.entries(parsed)) {
        if (typeof v === 'string') args[k] = v;
      }
    } catch {
      for (const m of jsonStr.matchAll(/"(\w+)":\s*"([^"]*)"/g)) {
        args[m[1]] = m[2];
      }
    }
  }

  if (toolName === 'github_find_examples') {
    const d = (args.keyword) || (args.repo);
    return d ? `Finding examples: ${d}` : 'Finding examples';
  }
  if (toolName === 'github_read_file') {
    const f = ((args.path) || '').split('/').pop();
    return f ? `Reading ${f}` : 'Reading file';
  }
  if (toolName === 'explore_hf_docs') {
    const d = (args.endpoint) || (args.query);
    return d ? `Exploring docs: ${d}` : 'Exploring docs';
  }
  if (toolName === 'fetch_hf_docs') {
    const p = ((args.url) || '').split('/').pop()?.replace(/\.md$/, '');
    return p ? `Reading docs: ${p}` : 'Fetching docs';
  }
  if (toolName === 'hf_inspect_dataset') {
    const d = args.dataset as string;
    return d ? `Inspecting dataset: ${d}` : 'Inspecting dataset';
  }
  if (toolName === 'hf_papers') {
    const op = args.operation as string;
    const detail = (args.query) || (args.arxiv_id);
    const opLabels: Record<string, string> = {
      trending: 'Browsing trending papers',
      search: 'Searching papers',
      paper_details: 'Reading paper details',
      read_paper: 'Reading paper',
      find_datasets: 'Finding paper datasets',
      find_models: 'Finding paper models',
      find_collections: 'Finding paper collections',
      find_all_resources: 'Finding paper resources',
    };
    const base = (op && opLabels[op]) || 'Searching papers';
    return detail ? `${base}: ${detail}` : base;
  }
  if (toolName === 'find_hf_api') {
    const d = (args.query) || (args.tag);
    return d ? `Finding API: ${d}` : 'Finding API endpoints';
  }
  if (toolName === 'hf_repo_files') {
    const d = (args.repo_id) || (args.repo);
    return d ? `Reading ${d} files` : 'Reading repo files';
  }
  return 'Researching';
}

function statusLabel(status: ActivityStatus): string {
  switch (status.type) {
    case 'thinking': return 'Thinking';
    case 'streaming': return 'Writing';
    case 'tool': {
      if (status.toolName === 'research' && status.description) {
        return formatResearchStatus(status.description);
      }
      const base = status.description || TOOL_LABELS[status.toolName] || `Running ${status.toolName}`;
      if (status.toolName === 'bash' && status.description && /install/i.test(status.description)) {
        return `${base} — this can take a few minutes, sit tight`;
      }
      return base;
    }
    case 'waiting-approval': return 'Waiting for approval';
    case 'cancelled': return 'What should the agent do instead?';
    default: return '';
  }
}

export default function ActivityStatusBar() {
  const activityStatus = useAgentStore(s => s.activityStatus);

  if (activityStatus.type === 'idle') return null;

  const label = statusLabel(activityStatus);

  return (
    <Box sx={{ px: 2, py: 0.5, minHeight: 28, display: 'flex', alignItems: 'center' }}>
      <Typography
        sx={{
          fontFamily: 'monospace',
          fontSize: '0.72rem',
          fontWeight: 500,
          letterSpacing: '0.02em',
          background: 'linear-gradient(90deg, var(--muted-text) 30%, var(--text) 50%, var(--muted-text) 70%)',
          backgroundSize: '250% 100%',
          backgroundClip: 'text',
          WebkitBackgroundClip: 'text',
          WebkitTextFillColor: 'transparent',
          animation: `${shimmer} 4s ease-in-out infinite`,
        }}
      >
        {label}{activityStatus.type !== 'cancelled' && '…'}
      </Typography>
    </Box>
  );
}