2025-07-15 20:51:12 -04:00
|
|
|
import { formatDistanceToNow } from "date-fns";
|
|
|
|
|
import { Thread } from "@langchain/langgraph-sdk";
|
2025-08-27 12:33:26 -07:00
|
|
|
import { ManagerGraphState } from "@openswe/shared/open-swe/manager/types";
|
2025-07-15 20:51:12 -04:00
|
|
|
import { ThreadMetadata } from "@/components/v2/types";
|
|
|
|
|
import { getThreadTitle } from "./thread";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculate human-readable last activity time from thread updated_at timestamp
|
|
|
|
|
*/
|
|
|
|
|
export function calculateLastActivity(updatedAt: string): string {
|
|
|
|
|
return formatDistanceToNow(new Date(updatedAt), { addSuffix: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts raw manager threads to ThreadMetadata objects for UI display
|
|
|
|
|
*/
|
|
|
|
|
export function threadsToMetadata(
|
|
|
|
|
threads: Thread<ManagerGraphState>[],
|
|
|
|
|
): ThreadMetadata[] {
|
|
|
|
|
return threads.map((thread): ThreadMetadata => {
|
|
|
|
|
const values = thread.values;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
id: thread.thread_id,
|
|
|
|
|
title: getThreadTitle(thread),
|
|
|
|
|
lastActivity: calculateLastActivity(thread.updated_at),
|
|
|
|
|
taskCount: values?.taskPlan?.tasks.length ?? 0,
|
|
|
|
|
repository: values?.targetRepository
|
|
|
|
|
? `${values.targetRepository.owner}/${values.targetRepository.repo}`
|
|
|
|
|
: "",
|
|
|
|
|
branch: values?.targetRepository?.branch || "main",
|
|
|
|
|
taskPlan: values?.taskPlan,
|
|
|
|
|
status: "idle" as const, // Default status - consumers can override with real status
|
|
|
|
|
githubIssue: values?.githubIssueId
|
|
|
|
|
? {
|
|
|
|
|
number: values?.githubIssueId,
|
|
|
|
|
url: `https://github.com/${values?.targetRepository?.owner}/${values?.targetRepository?.repo}/issues/${values?.githubIssueId}`,
|
|
|
|
|
}
|
|
|
|
|
: undefined,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|