返回 DeepSeek-Reasonix
composerInboxQueue.ts
根目录 / desktop / frontend / src / lib / composerInboxQueue.ts
1 import type { PendingGuidance } from "../components/ComposerGuidanceShelf";
2 import { asArray } from "./array";
3
4 export type InboxSnapshotLike = {
5 readonly?: boolean;
6 mutationsSupported?: boolean;
7 paused?: boolean;
8 recovered?: boolean;
9 recoveredCount?: number;
10 revision?: number;
11 sessionPath?: string;
12 items?: Array<{
13 id: string;
14 preview?: string;
15 state?: string;
16 intent?: string;
17 source?: string;
18 blockReason?: string;
19 }>;
20 };
21
22 export function inboxScopeKey(sessionPath?: string, workspaceScopeKey?: string): string {
23 return (sessionPath || "").trim() || workspaceScopeKey || "";
24 }
25
26 export function inboxSnapshotBelongsToScope(snapshotPath: string | undefined, scopeKey: string): boolean {
27 const path = (snapshotPath || "").trim();
28 if (!path || !scopeKey) return true;
29 if (scopeKey === path) return true;
30 return scopeKey.split("\u0000").includes(path);
31 }
32
33 export function localGuidanceFallback(previewKey: string): PendingGuidance[] {
34 return previewKey
35 .split("\n")
36 .filter(Boolean)
37 .map((text, i) => ({ id: `local-${i}`, text, submitText: text }));
38 }
39
40 export function guidanceFromInboxSnapshot(snap: InboxSnapshotLike | null | undefined): PendingGuidance[] {
41 const visible = asArray(snap?.items).filter((it) => it.state !== "steer_consumed" && it.state !== "running");
42 return visible.map((it) => ({
43 id: it.id,
44 text: it.preview || "",
45 submitText: "",
46 state: it.state,
47 intent: it.intent,
48 source: it.source,
49 blockReason: it.blockReason,
50 paused: Boolean(snap?.paused),
51 recoveredCount: snap?.paused && snap?.recovered
52 ? visible.length
53 : undefined,
54 }));
55 }
56
57 export async function hydrateEmptyGuidancePreviews(
58 items: PendingGuidance[],
59 readItem: (id: string) => Promise<{ displayText?: string; submitText?: string; rawText?: string }>,
60 ): Promise<PendingGuidance[]> {
61 const missing = items.filter((item) => !item.text.trim() && !item.id.startsWith("local-"));
62 if (missing.length === 0) return items;
63 await Promise.all(missing.map(async (item) => {
64 try {
65 const env = await readItem(item.id);
66 const text = (env.displayText || env.submitText || env.rawText || "").trim();
67 if (text) item.text = text;
68 } catch {
69 // Preview-only snapshot remains if the body cannot be read.
70 }
71 }));
72 return items;
73 }
74
75 export function mergeGuidanceSnapshot(durable: PendingGuidance[], fallback: PendingGuidance[]): PendingGuidance[] {
76 return durable.length > 0 ? durable : fallback;
77 }
78
78 lines TYPESCRIPT