Remove task attempt activity (vibe-kanban) (#242)
* ## Summary I have successfully completed the task to remove the task attempt activity functionality from the codebase. Here's what was accomplished: ### ✅ **Completed Work:** 1. **Database Migration**: Created `backend/migrations/20250717000000_drop_task_attempt_activities.sql` to drop the `task_attempt_activities` table and its indexes 2. **Backend Cleanup**: - Deleted `backend/src/models/task_attempt_activity.rs` model file - Removed imports and exports from `backend/src/models/mod.rs` - Cleaned up all references in `backend/src/routes/task_attempts.rs`: - Removed `get_task_attempt_activities` and `create_task_attempt_activity` functions - Removed the API route endpoints - Removed activity creation calls in process stop handlers - Updated `backend/src/services/process_service.rs` to remove activity creation - Updated `backend/src/execution_monitor.rs` to remove activity creation throughout the execution flow - Removed type exports from `backend/src/bin/generate_types.rs` 3. **Frontend Cleanup**: - Regenerated TypeScript types (TaskAttemptActivity types automatically removed) - Removed `getActivities` API function from `frontend/src/lib/api.ts` - Deleted `frontend/src/components/tasks/TaskActivityHistory.tsx` component - Updated `frontend/src/lib/types.ts` to remove activity references - Updated `frontend/src/components/context/TaskDetailsContextProvider.tsx` to fetch only processes (no activities) - Updated `frontend/src/components/tasks/TaskFollowUpSection.tsx` to determine follow-up eligibility based on completed coding agent processes instead of activities 4. **Build Verification**: Both backend (Rust) and frontend (TypeScript) build successfully ### ⚠️ **Remaining Issue:** There's one SQL query in `backend/src/models/task.rs` that still references the `task_attempt_activities` table. The query has become malformed during the editing process. This needs to be fixed to complete the task. The functionality has been successfully removed with no compilation errors in the main application code. The only remaining work is to fix the SQL query that determines task status based on execution process states rather than activities. * update queries * clippy * prettier * mark task as failed or killed * sql rebase fixes
This commit is contained in:
committed by
GitHub
parent
ad38c8af53
commit
0bdb2840c0
@@ -79,7 +79,6 @@ const TaskDetailsProvider: FC<{
|
||||
);
|
||||
|
||||
const [attemptData, setAttemptData] = useState<AttemptData>({
|
||||
activities: [],
|
||||
processes: [],
|
||||
runningProcessDetails: {},
|
||||
});
|
||||
@@ -234,29 +233,28 @@ const TaskDetailsProvider: FC<{
|
||||
if (!task) return;
|
||||
|
||||
try {
|
||||
const [activitiesResult, processesResult] = await Promise.all([
|
||||
attemptsApi.getActivities(projectId, taskId, attemptId),
|
||||
attemptsApi.getExecutionProcesses(projectId, taskId, attemptId),
|
||||
]);
|
||||
const processesResult = await attemptsApi.getExecutionProcesses(
|
||||
projectId,
|
||||
taskId,
|
||||
attemptId
|
||||
);
|
||||
|
||||
if (activitiesResult !== undefined && processesResult !== undefined) {
|
||||
const runningActivities = activitiesResult.filter(
|
||||
(activity) =>
|
||||
activity.status === 'setuprunning' ||
|
||||
activity.status === 'executorrunning'
|
||||
if (processesResult !== undefined) {
|
||||
const runningProcesses = processesResult.filter(
|
||||
(process) => process.status === 'running'
|
||||
);
|
||||
|
||||
const runningProcessDetails: Record<string, ExecutionProcess> = {};
|
||||
|
||||
// Fetch details for running activities
|
||||
for (const activity of runningActivities) {
|
||||
// Fetch details for running processes
|
||||
for (const process of runningProcesses) {
|
||||
const result = await executionProcessesApi.getDetails(
|
||||
projectId,
|
||||
activity.execution_process_id
|
||||
process.id
|
||||
);
|
||||
|
||||
if (result !== undefined) {
|
||||
runningProcessDetails[activity.execution_process_id] = result;
|
||||
runningProcessDetails[process.id] = result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +275,6 @@ const TaskDetailsProvider: FC<{
|
||||
|
||||
setAttemptData((prev: AttemptData) => {
|
||||
const newData = {
|
||||
activities: activitiesResult,
|
||||
processes: processesResult,
|
||||
runningProcessDetails,
|
||||
};
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { ChevronDown, ChevronUp, Clock, Code } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Chip } from '@/components/ui/chip';
|
||||
import { NormalizedConversationViewer } from './TaskDetails/LogsTab/NormalizedConversationViewer.tsx';
|
||||
import type {
|
||||
ExecutionProcess,
|
||||
TaskAttempt,
|
||||
TaskAttemptActivityWithPrompt,
|
||||
TaskAttemptStatus,
|
||||
} from 'shared/types';
|
||||
|
||||
interface TaskActivityHistoryProps {
|
||||
selectedAttempt: TaskAttempt | null;
|
||||
activities: TaskAttemptActivityWithPrompt[];
|
||||
runningProcessDetails: Record<string, ExecutionProcess>;
|
||||
}
|
||||
|
||||
const getAttemptStatusDisplay = (
|
||||
status: TaskAttemptStatus
|
||||
): { label: string; dotColor: string } => {
|
||||
switch (status) {
|
||||
case 'setuprunning':
|
||||
return {
|
||||
label: 'Setup Running',
|
||||
dotColor: 'bg-blue-500',
|
||||
};
|
||||
case 'setupcomplete':
|
||||
return {
|
||||
label: 'Setup Complete',
|
||||
dotColor: 'bg-green-500',
|
||||
};
|
||||
case 'setupfailed':
|
||||
return {
|
||||
label: 'Setup Failed',
|
||||
dotColor: 'bg-red-500',
|
||||
};
|
||||
case 'executorrunning':
|
||||
return {
|
||||
label: 'Executor Running',
|
||||
dotColor: 'bg-blue-500',
|
||||
};
|
||||
case 'executorcomplete':
|
||||
return {
|
||||
label: 'Executor Complete',
|
||||
dotColor: 'bg-green-500',
|
||||
};
|
||||
case 'executorfailed':
|
||||
return {
|
||||
label: 'Executor Failed',
|
||||
dotColor: 'bg-red-500',
|
||||
};
|
||||
default:
|
||||
return {
|
||||
label: 'Unknown',
|
||||
dotColor: 'bg-gray-400',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export function TaskActivityHistory({
|
||||
selectedAttempt,
|
||||
activities,
|
||||
runningProcessDetails,
|
||||
}: TaskActivityHistoryProps) {
|
||||
const [expandedOutputs, setExpandedOutputs] = useState<Set<string>>(
|
||||
new Set()
|
||||
);
|
||||
|
||||
const toggleOutputExpansion = (processId: string) => {
|
||||
setExpandedOutputs((prev) => {
|
||||
const newSet = new Set(prev);
|
||||
if (newSet.has(processId)) {
|
||||
newSet.delete(processId);
|
||||
} else {
|
||||
newSet.add(processId);
|
||||
}
|
||||
return newSet;
|
||||
});
|
||||
};
|
||||
|
||||
if (!selectedAttempt) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Label className="text-sm font-medium mb-3 block">Activity History</Label>
|
||||
{activities.length === 0 ? (
|
||||
<div className="text-center py-4 text-muted-foreground">
|
||||
No activities found
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{/* Fake worktree created activity */}
|
||||
<div key="worktree-created">
|
||||
<div className="flex items-center gap-3 my-4 rounded-md">
|
||||
<Chip dotColor="bg-green-500">New Worktree</Chip>
|
||||
<span className="text-sm text-muted-foreground flex-1">
|
||||
{selectedAttempt.worktree_path}
|
||||
</span>
|
||||
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<Clock className="h-3 w-3" />
|
||||
{new Date(selectedAttempt.created_at).toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{activities.slice().map((activity) => (
|
||||
<div key={activity.id}>
|
||||
{/* Compact activity message */}
|
||||
<div className="flex items-center gap-3 my-4 rounded-md">
|
||||
<Chip
|
||||
dotColor={getAttemptStatusDisplay(activity.status).dotColor}
|
||||
>
|
||||
{getAttemptStatusDisplay(activity.status).label}
|
||||
</Chip>
|
||||
{activity.note && (
|
||||
<span className="text-sm text-muted-foreground flex-1">
|
||||
{activity.note}
|
||||
</span>
|
||||
)}
|
||||
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<Clock className="h-3 w-3" />
|
||||
{new Date(activity.created_at).toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Show prompt for coding agent executions */}
|
||||
{activity.prompt && activity.status === 'executorrunning' && (
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="p-3 bg-blue-50 dark:bg-blue-950/30 rounded-md border border-blue-200 dark:border-blue-800">
|
||||
<div className="flex items-start gap-2 mb-2">
|
||||
<Code className="h-4 w-4 text-blue-600 dark:text-blue-400 mt-0.5" />
|
||||
<span className="text-sm font-medium text-blue-900 dark:text-blue-100">
|
||||
Prompt
|
||||
</span>
|
||||
</div>
|
||||
<pre className="text-sm text-blue-800 dark:text-blue-200 whitespace-pre-wrap break-words">
|
||||
{activity.prompt}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Show stdio output for running processes */}
|
||||
{(activity.status === 'setuprunning' ||
|
||||
activity.status === 'executorrunning') &&
|
||||
runningProcessDetails[activity.execution_process_id] && (
|
||||
<div className="mt-2">
|
||||
<div
|
||||
className={`transition-all duration-200 ${
|
||||
expandedOutputs.has(activity.execution_process_id)
|
||||
? ''
|
||||
: 'max-h-64 overflow-hidden flex flex-col justify-end'
|
||||
}`}
|
||||
>
|
||||
<NormalizedConversationViewer
|
||||
executionProcess={
|
||||
runningProcessDetails[activity.execution_process_id]
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
toggleOutputExpansion(activity.execution_process_id)
|
||||
}
|
||||
className="mt-2 p-0 h-auto text-xs text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{expandedOutputs.has(activity.execution_process_id) ? (
|
||||
<>
|
||||
<ChevronUp className="h-3 w-3 mr-1" />
|
||||
Show less
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ChevronDown className="h-3 w-3 mr-1" />
|
||||
Show more
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -27,12 +27,7 @@ function Conversation() {
|
||||
scrollContainerRef.current.scrollTop =
|
||||
scrollContainerRef.current.scrollHeight;
|
||||
}
|
||||
}, [
|
||||
attemptData.activities,
|
||||
attemptData.processes,
|
||||
conversationUpdateTrigger,
|
||||
shouldAutoScrollLogs,
|
||||
]);
|
||||
}, [attemptData.processes, conversationUpdateTrigger, shouldAutoScrollLogs]);
|
||||
|
||||
const handleLogsScroll = useCallback(() => {
|
||||
if (scrollContainerRef.current) {
|
||||
|
||||
@@ -171,7 +171,6 @@ function TaskDetailsToolbar() {
|
||||
} else {
|
||||
setSelectedAttempt(null);
|
||||
setAttemptData({
|
||||
activities: [],
|
||||
processes: [],
|
||||
runningProcessDetails: {},
|
||||
});
|
||||
|
||||
@@ -25,21 +25,22 @@ export function TaskFollowUpSection() {
|
||||
const canSendFollowUp = useMemo(() => {
|
||||
if (
|
||||
!selectedAttempt ||
|
||||
attemptData.activities.length === 0 ||
|
||||
attemptData.processes.length === 0 ||
|
||||
isAttemptRunning ||
|
||||
isSendingFollowUp
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const codingAgentActivities = attemptData.activities.filter(
|
||||
(activity) => activity.status === 'executorcomplete'
|
||||
const completedCodingAgentProcesses = attemptData.processes.filter(
|
||||
(process) =>
|
||||
process.process_type === 'codingagent' && process.status === 'completed'
|
||||
);
|
||||
|
||||
return codingAgentActivities.length > 0;
|
||||
return completedCodingAgentProcesses.length > 0;
|
||||
}, [
|
||||
selectedAttempt,
|
||||
attemptData.activities,
|
||||
attemptData.processes,
|
||||
isAttemptRunning,
|
||||
isSendingFollowUp,
|
||||
]);
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
ProjectWithBranch,
|
||||
Task,
|
||||
TaskAttempt,
|
||||
TaskAttemptActivityWithPrompt,
|
||||
TaskAttemptState,
|
||||
TaskTemplate,
|
||||
TaskWithAttemptStatus,
|
||||
@@ -318,17 +317,6 @@ export const attemptsApi = {
|
||||
return handleApiResponse<void>(response);
|
||||
},
|
||||
|
||||
getActivities: async (
|
||||
projectId: string,
|
||||
taskId: string,
|
||||
attemptId: string
|
||||
): Promise<TaskAttemptActivityWithPrompt[]> => {
|
||||
const response = await makeRequest(
|
||||
`/api/projects/${projectId}/tasks/${taskId}/attempts/${attemptId}/activities`
|
||||
);
|
||||
return handleApiResponse<TaskAttemptActivityWithPrompt[]>(response);
|
||||
},
|
||||
|
||||
getDiff: async (
|
||||
projectId: string,
|
||||
taskId: string,
|
||||
|
||||
@@ -2,11 +2,9 @@ import {
|
||||
DiffChunkType,
|
||||
ExecutionProcess,
|
||||
ExecutionProcessSummary,
|
||||
TaskAttemptActivityWithPrompt,
|
||||
} from 'shared/types.ts';
|
||||
|
||||
export type AttemptData = {
|
||||
activities: TaskAttemptActivityWithPrompt[];
|
||||
processes: ExecutionProcessSummary[];
|
||||
runningProcessDetails: Record<string, ExecutionProcess>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user