Skip to content

Commit be60c58

Browse files
committed
feat: introduce agent tracing functionality and enhance UI components
- Added AgentTraceProvider and context for managing agent run states and steps. - Implemented AgentsView component for displaying current agent runs and their statuses. - Enhanced global CSS with new styles for ghost buttons and subtle variations. - Updated layout to include AgentTraceProvider and integrated new agent view into the routing. - Refined existing components to support the new agent tracing features, improving overall user experience.
1 parent f3887e5 commit be60c58

File tree

14 files changed

+548
-53
lines changed

14 files changed

+548
-53
lines changed

app/globals.css

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,35 @@
133133
box-shadow: none;
134134
}
135135

136+
.ui-ghost-button {
137+
min-height: 2.5rem;
138+
min-width: 2.5rem;
139+
border: 1px solid color-mix(in srgb, var(--border) 92%, transparent);
140+
background: color-mix(in srgb, var(--bg-elevated) 88%, transparent);
141+
color: var(--text-secondary);
142+
box-shadow: var(--shadow-xs);
143+
}
144+
145+
.ui-ghost-button:hover {
146+
border-color: var(--border-hover);
147+
background: color-mix(in srgb, var(--text-primary) 7%, var(--bg-elevated));
148+
color: var(--text-primary);
149+
}
150+
151+
.ui-ghost-button--subtle {
152+
min-height: 2.125rem;
153+
min-width: 2.125rem;
154+
border: 1px solid color-mix(in srgb, var(--border) 88%, transparent);
155+
background: color-mix(in srgb, var(--bg-elevated) 80%, transparent);
156+
color: var(--text-secondary);
157+
}
158+
159+
.ui-ghost-button--subtle:hover {
160+
border-color: var(--border-hover);
161+
background: color-mix(in srgb, var(--text-primary) 6%, var(--bg-elevated));
162+
color: var(--text-primary);
163+
}
164+
136165
@media (max-width: 768px) {
137166
body {
138167
font-size: 15px;

app/layout.tsx

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { EditorProvider } from '@/context/editor-context'
77
import { LocalProvider } from '@/context/local-context'
88
import { ViewProvider } from '@/context/view-context'
99
import { GitHubAuthProvider } from '@/context/github-auth-context'
10+
import { AgentTraceProvider } from '@/context/agent-trace-context'
1011
import { PluginProvider } from '@/context/plugin-context'
1112
import { PreviewProvider } from '@/context/preview-context'
1213
import { ChatAppearanceProvider } from '@/context/chat-appearance-context'
@@ -44,29 +45,31 @@ export default function RootLayout({ children }: { children: React.ReactNode })
4445
<ThemeProvider>
4546
<GatewayProvider>
4647
<GitHubAuthProvider>
47-
<RepoProvider>
48-
<EditorProvider>
49-
<LocalProvider>
50-
<ViewProvider>
51-
<LayoutProvider>
52-
<ThreadProvider>
53-
<AppModeProvider>
54-
<PreviewProvider>
55-
<ChatAppearanceProvider>
56-
<PluginProvider>
57-
<ToastProvider>
58-
<Suspense fallback={<AppSkeleton />}>{children}</Suspense>
59-
</ToastProvider>
60-
</PluginProvider>
61-
</ChatAppearanceProvider>
62-
</PreviewProvider>
63-
</AppModeProvider>
64-
</ThreadProvider>
65-
</LayoutProvider>
66-
</ViewProvider>
67-
</LocalProvider>
68-
</EditorProvider>
69-
</RepoProvider>
48+
<AgentTraceProvider>
49+
<RepoProvider>
50+
<EditorProvider>
51+
<LocalProvider>
52+
<ViewProvider>
53+
<LayoutProvider>
54+
<ThreadProvider>
55+
<AppModeProvider>
56+
<PreviewProvider>
57+
<ChatAppearanceProvider>
58+
<PluginProvider>
59+
<ToastProvider>
60+
<Suspense fallback={<AppSkeleton />}>{children}</Suspense>
61+
</ToastProvider>
62+
</PluginProvider>
63+
</ChatAppearanceProvider>
64+
</PreviewProvider>
65+
</AppModeProvider>
66+
</ThreadProvider>
67+
</LayoutProvider>
68+
</ViewProvider>
69+
</LocalProvider>
70+
</EditorProvider>
71+
</RepoProvider>
72+
</AgentTraceProvider>
7073
</GitHubAuthProvider>
7174
</GatewayProvider>
7275
</ThemeProvider>

app/page.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,13 +532,21 @@ export default function EditorLayout() {
532532
})}
533533
</div>
534534

535+
<button
536+
type="button"
537+
onClick={() => setView('agents')}
538+
className="ui-ghost-button flex h-10 w-10 shrink-0 items-center justify-center rounded-xl transition"
539+
title="Agents"
540+
>
541+
<Icon icon="lucide:bot" width={18} height={18} />
542+
</button>
535543
<button
536544
type="button"
537545
onClick={() => setView('settings')}
538-
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-[var(--text-secondary)] transition hover:bg-[var(--bg-elevated)] hover:text-[var(--text-primary)]"
546+
className="ui-ghost-button flex h-10 w-10 shrink-0 items-center justify-center rounded-xl transition"
539547
title="Settings"
540548
>
541-
<Icon icon="lucide:settings-2" width={16} height={16} />
549+
<Icon icon="lucide:settings-2" width={18} height={18} />
542550
</button>
543551
</div>
544552
</div>

components/chat/chat-input-bar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ export function ChatInputBar({
616616
</button>
617617
<button
618618
onClick={onImageAttach}
619-
className="flex h-7 w-7 items-center justify-center rounded-lg border border-[var(--border)] bg-[var(--bg)] text-[var(--text-disabled)] hover:text-[var(--text-secondary)] hover:border-[var(--border-hover)] transition-colors cursor-pointer"
619+
className="ui-ghost-button--subtle flex h-8 w-8 items-center justify-center rounded-xl transition-colors cursor-pointer"
620620
title="Attach image"
621621
>
622622
<Icon icon="lucide:image-plus" width={14} height={14} />

components/mode-selector.tsx

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,24 @@ import { Icon } from '@iconify/react'
66
export type AgentMode = 'ask' | 'agent' | 'plan'
77

88
const MODES: Array<{ id: AgentMode; label: string; icon: string; desc: string }> = [
9-
{ id: 'ask', label: 'Ask', icon: 'lucide:message-square', desc: 'Discuss and answer questions — no code changes' },
10-
{ id: 'agent', label: 'Agent', icon: 'lucide:zap', desc: 'Autonomous code changes and edits' },
11-
{ id: 'plan', label: 'Plan', icon: 'lucide:list-checks', desc: 'Outline steps first, then execute with approval' },
9+
{
10+
id: 'ask',
11+
label: 'Ask',
12+
icon: 'lucide:message-square',
13+
desc: 'Discuss and answer questions — no code changes',
14+
},
15+
{
16+
id: 'agent',
17+
label: 'Agent',
18+
icon: 'lucide:zap',
19+
desc: 'Autonomous code changes and edits',
20+
},
21+
{
22+
id: 'plan',
23+
label: 'Plan',
24+
icon: 'lucide:list-checks',
25+
desc: 'Outline steps first, then execute with approval',
26+
},
1227
]
1328

1429
interface Props {
@@ -23,7 +38,7 @@ export function ModeSelector({ mode, onChange, size = 'sm' }: Props) {
2338
const [pill, setPill] = useState({ left: 0, width: 0 })
2439

2540
const recalcPill = useCallback(() => {
26-
const idx = MODES.findIndex(m => m.id === mode)
41+
const idx = MODES.findIndex((m) => m.id === mode)
2742
const btn = btnRefs.current[idx]
2843
const container = containerRef.current
2944
if (btn && container) {
@@ -53,34 +68,37 @@ export function ModeSelector({ mode, onChange, size = 'sm' }: Props) {
5368
return (
5469
<div
5570
ref={containerRef}
56-
className={`relative inline-flex items-center rounded-[10px] bg-[color-mix(in_srgb,var(--text-primary)_6%,transparent)] ${
57-
isMd ? 'gap-0.5 p-[3px]' : 'gap-px p-[2px]'
71+
className={`relative inline-flex items-center rounded-[12px] border border-[color-mix(in_srgb,var(--border)_92%,transparent)] bg-[color-mix(in_srgb,var(--bg-elevated)_92%,transparent)] shadow-[var(--shadow-xs)] ${
72+
isMd ? 'gap-0.5 p-[4px]' : 'gap-[2px] p-[3px]'
5873
}`}
5974
>
6075
<span
61-
className={`absolute rounded-lg pointer-events-none bg-[color-mix(in_srgb,var(--text-primary)_10%,var(--bg))] ${
76+
className={`absolute rounded-[10px] pointer-events-none bg-[color-mix(in_srgb,var(--text-primary)_10%,var(--bg))] ${
6277
isMd
63-
? 'top-[3px] h-[calc(100%-6px)] shadow-[0_1px_3px_rgba(0,0,0,0.12),0_0_0_1px_color-mix(in_srgb,var(--text-primary)_12%,transparent)]'
64-
: 'top-[2px] h-[calc(100%-4px)] shadow-[0_1px_2px_rgba(0,0,0,0.1),0_0_0_1px_color-mix(in_srgb,var(--text-primary)_10%,transparent)]'
78+
? 'top-[4px] h-[calc(100%-8px)] shadow-[0_2px_6px_rgba(0,0,0,0.16),0_0_0_1px_color-mix(in_srgb,var(--brand)_18%,transparent)]'
79+
: 'top-[3px] h-[calc(100%-6px)] shadow-[0_2px_5px_rgba(0,0,0,0.14),0_0_0_1px_color-mix(in_srgb,var(--brand)_14%,transparent)]'
6580
}`}
6681
style={{
6782
left: pill.left,
6883
width: pill.width,
69-
transition: 'left 300ms cubic-bezier(0.22, 1, 0.36, 1), width 300ms cubic-bezier(0.22, 1, 0.36, 1)',
84+
transition:
85+
'left 300ms cubic-bezier(0.22, 1, 0.36, 1), width 300ms cubic-bezier(0.22, 1, 0.36, 1)',
7086
opacity: pill.width > 0 ? 1 : 0,
7187
}}
7288
/>
7389
{MODES.map((m, i) => (
7490
<button
7591
key={m.id}
76-
ref={el => { btnRefs.current[i] = el }}
92+
ref={(el) => {
93+
btnRefs.current[i] = el
94+
}}
7795
onClick={() => onChange(m.id)}
78-
className={`relative z-[1] flex items-center rounded-lg font-medium transition-colors duration-200 cursor-pointer select-none ${
79-
isMd ? 'gap-1.5 px-3.5 py-1.5 text-[13px]' : 'gap-1 px-2.5 py-1 text-[11px]'
96+
className={`relative z-[1] flex items-center rounded-[10px] font-medium transition-colors duration-200 cursor-pointer select-none ${
97+
isMd ? 'gap-1.5 px-3.5 py-2 text-[13px]' : 'gap-1.5 px-3 py-1.5 text-[12px]'
8098
} ${
8199
mode === m.id
82100
? 'text-[var(--text-primary)]'
83-
: 'text-[var(--text-disabled)] hover:text-[var(--text-tertiary)]'
101+
: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)]'
84102
}`}
85103
title={m.desc}
86104
>

components/provider-selector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export function ProviderSelector({ size = 'sm' }: Props) {
113113
{open && (
114114
<>
115115
<div className="fixed inset-0 z-[9990]" onClick={() => setOpen(false)} />
116-
<div className="absolute bottom-full left-0 mb-1.5 z-[9991] w-60 bg-[var(--bg-elevated)] border border-[var(--border)] rounded-xl shadow-xl overflow-hidden">
116+
<div className="absolute bottom-full left-0 mb-1.5 z-[9991] w-64 bg-[var(--bg-elevated)] border border-[var(--border)] rounded-2xl shadow-xl overflow-hidden">
117117
<div className="px-3 pt-2.5 pb-1.5">
118118
<span className="text-[10px] font-semibold uppercase tracking-wider text-[var(--text-disabled)]">
119119
Provider

components/view-router.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ const PlannerView = dynamic(
4444
() => import('@/components/views/planner-view').then((m) => m.PlannerView),
4545
{ ssr: false },
4646
)
47+
const AgentsView = dynamic(
48+
() => import('@/components/views/agents-view').then((m) => m.AgentsView),
49+
{ ssr: false },
50+
)
4751
const WorkshopView = dynamic(
4852
() => import('@/components/views/workshop-view').then((m) => m.WorkshopView),
4953
{ ssr: false },
@@ -129,6 +133,7 @@ export function ViewRouter() {
129133
{activeView === 'chat' && <AgentPanel />}
130134
{(activeView === 'editor' || activeView === 'preview') && <EditorView />}
131135
{activeView === 'planner' && <PlannerView />}
136+
{activeView === 'agents' && <AgentsView />}
132137
{activeView === 'git' && <GitView />}
133138
{activeView === 'kanban' && <KanbanView />}
134139
{activeView === 'skills' && <SkillsView />}

0 commit comments

Comments
 (0)