134 lines
4.1 KiB
TypeScript
134 lines
4.1 KiB
TypeScript
export const CLAWD_TASK_KIND = "clawd_chat";
|
|
|
|
export type ClawdTaskStatus =
|
|
| "queued"
|
|
| "running"
|
|
| "completed"
|
|
| "failed"
|
|
| "canceled";
|
|
|
|
export type ClawdTaskProgressPayload = Record<string, unknown>;
|
|
|
|
export type ClawdTaskMetadata = {
|
|
composerMode: "clawd";
|
|
source: "openclaw";
|
|
taskKind: typeof CLAWD_TASK_KIND;
|
|
status: ClawdTaskStatus;
|
|
userMessageId: string;
|
|
assistantMessageId: string;
|
|
processingHint: string;
|
|
progressEvents: ClawdTaskProgressPayload[];
|
|
skillTagId?: string | null;
|
|
skillTagName?: string | null;
|
|
requestId?: string | null;
|
|
error?: string | null;
|
|
upstreamTaskId?: string | null;
|
|
upstreamTaskKey?: string | null;
|
|
upstreamEventsEndpoint?: string | null;
|
|
upstreamLastEventId?: number | null;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|
|
|
|
const CLAWD_TASK_STATUSES = new Set<ClawdTaskStatus>([
|
|
"queued",
|
|
"running",
|
|
"completed",
|
|
"failed",
|
|
"canceled",
|
|
]);
|
|
|
|
export function normalizeClawdTaskMetadata(
|
|
value: unknown
|
|
): ClawdTaskMetadata | null {
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
const raw = value as Record<string, unknown>;
|
|
if (raw.taskKind !== CLAWD_TASK_KIND || raw.composerMode !== "clawd") {
|
|
return null;
|
|
}
|
|
|
|
const status = String(raw.status || "") as ClawdTaskStatus;
|
|
const userMessageId = String(raw.userMessageId || "").trim();
|
|
const assistantMessageId = String(raw.assistantMessageId || "").trim();
|
|
if (
|
|
!CLAWD_TASK_STATUSES.has(status) ||
|
|
!userMessageId ||
|
|
!assistantMessageId
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
const createdAt = Number(raw.createdAt);
|
|
const updatedAt = Number(raw.updatedAt);
|
|
const upstreamLastEventId = Number(raw.upstreamLastEventId);
|
|
return {
|
|
composerMode: "clawd",
|
|
source: "openclaw",
|
|
taskKind: CLAWD_TASK_KIND,
|
|
status,
|
|
userMessageId,
|
|
assistantMessageId,
|
|
processingHint: String(raw.processingHint || "").trim(),
|
|
progressEvents: Array.isArray(raw.progressEvents)
|
|
? raw.progressEvents.filter(
|
|
(item): item is ClawdTaskProgressPayload =>
|
|
Boolean(item) && typeof item === "object" && !Array.isArray(item)
|
|
)
|
|
: [],
|
|
skillTagId: raw.skillTagId ? String(raw.skillTagId) : null,
|
|
skillTagName: raw.skillTagName ? String(raw.skillTagName) : null,
|
|
requestId: raw.requestId ? String(raw.requestId) : null,
|
|
error: raw.error ? String(raw.error) : null,
|
|
upstreamTaskId: raw.upstreamTaskId ? String(raw.upstreamTaskId) : null,
|
|
upstreamTaskKey: raw.upstreamTaskKey ? String(raw.upstreamTaskKey) : null,
|
|
upstreamEventsEndpoint: raw.upstreamEventsEndpoint
|
|
? String(raw.upstreamEventsEndpoint)
|
|
: null,
|
|
upstreamLastEventId: Number.isFinite(upstreamLastEventId)
|
|
? Math.max(0, Math.trunc(upstreamLastEventId))
|
|
: null,
|
|
createdAt: Number.isFinite(createdAt) ? createdAt : Date.now(),
|
|
updatedAt: Number.isFinite(updatedAt) ? updatedAt : Date.now(),
|
|
};
|
|
}
|
|
|
|
export function isPendingClawdTaskStatus(status: ClawdTaskStatus) {
|
|
return status === "queued" || status === "running";
|
|
}
|
|
|
|
export function appendClawdTaskProgress(
|
|
current: ClawdTaskProgressPayload[],
|
|
progress: ClawdTaskProgressPayload,
|
|
maxItems = 200
|
|
) {
|
|
const eventId = String(progress.event_id || "").trim();
|
|
const sequence = String(progress.sequence || "").trim();
|
|
const key = eventId
|
|
? `event:${eventId}`
|
|
: sequence
|
|
? `sequence:${sequence}`
|
|
: [
|
|
String(progress.step_code || ""),
|
|
String(progress.step_state || ""),
|
|
String(progress.message || progress.display || ""),
|
|
].join("|");
|
|
const next = current.some((item) => {
|
|
const itemEventId = String(item.event_id || "").trim();
|
|
const itemSequence = String(item.sequence || "").trim();
|
|
const itemKey = itemEventId
|
|
? `event:${itemEventId}`
|
|
: itemSequence
|
|
? `sequence:${itemSequence}`
|
|
: [
|
|
String(item.step_code || ""),
|
|
String(item.step_state || ""),
|
|
String(item.message || item.display || ""),
|
|
].join("|");
|
|
return itemKey === key;
|
|
})
|
|
? current
|
|
: [...current, progress];
|
|
|
|
return next.slice(-Math.max(1, maxItems));
|
|
}
|