Merge pull request #236 from multica-ai/agent/lambda/b34769c1

fix(issues): show execution logs for mention-triggered agent tasks
This commit is contained in:
Jiayuan Zhang 2026-03-31 18:52:19 +08:00 committed by GitHub
commit 7188fd8f2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 17 additions and 16 deletions

View file

@ -161,6 +161,9 @@ vi.mock("@/shared/api", () => ({
listIssueSubscribers: vi.fn().mockResolvedValue([]),
subscribeToIssue: vi.fn().mockResolvedValue(undefined),
unsubscribeFromIssue: vi.fn().mockResolvedValue(undefined),
getActiveTaskForIssue: vi.fn().mockResolvedValue({ task: null }),
listTasksByIssue: vi.fn().mockResolvedValue([]),
listTaskMessages: vi.fn().mockResolvedValue([]),
},
}));

View file

@ -97,12 +97,10 @@ function buildTimeline(msgs: TaskMessagePayload[]): TimelineItem[] {
interface AgentLiveCardProps {
issueId: string;
assigneeType: string | null;
assigneeId: string | null;
agentName?: string;
}
export function AgentLiveCard({ issueId, assigneeType, assigneeId, agentName }: AgentLiveCardProps) {
export function AgentLiveCard({ issueId, agentName }: AgentLiveCardProps) {
const { getActorName } = useActorName();
const [activeTask, setActiveTask] = useState<AgentTask | null>(null);
const [items, setItems] = useState<TimelineItem[]>([]);
@ -113,11 +111,6 @@ export function AgentLiveCard({ issueId, assigneeType, assigneeId, agentName }:
// Check for active task on mount
useEffect(() => {
if (assigneeType !== "agent" || !assigneeId) {
setActiveTask(null);
return;
}
let cancelled = false;
api.getActiveTaskForIssue(issueId).then(({ task }) => {
if (!cancelled) {
@ -135,7 +128,7 @@ export function AgentLiveCard({ issueId, assigneeType, assigneeId, agentName }:
}).catch(() => {});
return () => { cancelled = true; };
}, [issueId, assigneeType, assigneeId]);
}, [issueId]);
// Handle real-time task messages
useWSEvent(
@ -280,17 +273,15 @@ export function AgentLiveCard({ issueId, assigneeType, assigneeId, agentName }:
interface TaskRunHistoryProps {
issueId: string;
assigneeType: string | null;
}
export function TaskRunHistory({ issueId, assigneeType }: TaskRunHistoryProps) {
export function TaskRunHistory({ issueId }: TaskRunHistoryProps) {
const [tasks, setTasks] = useState<AgentTask[]>([]);
const [open, setOpen] = useState(false);
useEffect(() => {
if (assigneeType !== "agent") return;
api.listTasksByIssue(issueId).then(setTasks).catch(() => {});
}, [issueId, assigneeType]);
}, [issueId]);
// Refresh when a task completes
useWSEvent(

View file

@ -672,15 +672,13 @@ export function IssueDetail({ issueId, onDelete, defaultSidebarOpen = true, layo
<div className="mt-4">
<AgentLiveCard
issueId={id}
assigneeType={issue.assignee_type}
assigneeId={issue.assignee_id}
agentName={issue.assignee_type === "agent" && issue.assignee_id ? getActorName("agent", issue.assignee_id) : undefined}
/>
</div>
{/* Agent execution history */}
<div className="mt-3">
<TaskRunHistory issueId={id} assigneeType={issue.assignee_type} />
<TaskRunHistory issueId={id} />
</div>
{/* Timeline entries */}

View file

@ -477,12 +477,20 @@ func (h *Handler) ReportTaskMessages(w http.ResponseWriter, r *http.Request) {
func (h *Handler) ListTaskMessages(w http.ResponseWriter, r *http.Request) {
taskID := chi.URLParam(r, "taskId")
task, err := h.Queries.GetAgentTask(r.Context(), parseUUID(taskID))
if err != nil {
writeError(w, http.StatusNotFound, "task not found")
return
}
messages, err := h.Queries.ListTaskMessages(r.Context(), parseUUID(taskID))
if err != nil {
writeError(w, http.StatusInternalServerError, "failed to list task messages")
return
}
issueID := uuidToString(task.IssueID)
resp := make([]protocol.TaskMessagePayload, len(messages))
for i, m := range messages {
var input map[string]any
@ -491,6 +499,7 @@ func (h *Handler) ListTaskMessages(w http.ResponseWriter, r *http.Request) {
}
resp[i] = protocol.TaskMessagePayload{
TaskID: taskID,
IssueID: issueID,
Seq: int(m.Seq),
Type: m.Type,
Tool: m.Tool.String,