-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathPromptsTab.tsx
More file actions
158 lines (144 loc) · 5.35 KB
/
PromptsTab.tsx
File metadata and controls
158 lines (144 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import React, { useMemo } from "react";
import { Span, Trace } from "@/types/traces";
import { PromptWithLatestVersion, PromptVersion } from "@/types/prompts";
import { PromptLibraryMetadata } from "@/types/playground";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/ui/accordion";
import get from "lodash/get";
import { FileTerminal, GitCommitVertical } from "lucide-react";
import useAppStore from "@/store/AppStore";
import { useIsFeatureEnabled } from "@/contexts/feature-toggles-provider";
import { usePermissions } from "@/contexts/PermissionsContext";
import { FeatureToggleKeys } from "@/types/feature-toggles";
import TryInPlaygroundButton from "@/v1/pages/PromptPage/TryInPlaygroundButton";
import PromptContentView, {
CustomUseInPlaygroundButton,
} from "./PromptContentView";
// Helper to ensure template is always a string for PromptVersion
// The template from trace metadata can be either a string (legacy) or parsed JSON object (new format)
const normalizeTemplate = (template: unknown): string => {
if (typeof template === "string") {
return template;
}
if (template !== null && template !== undefined) {
return JSON.stringify(template, null, 2);
}
return "";
};
type PromptsTabProps = {
data: Trace | Span;
search?: string;
};
const convertRawPromptToPromptWithLatestVersion = (
rawPrompt: PromptLibraryMetadata,
): PromptWithLatestVersion => {
const date = new Date().toISOString();
// Use existing metadata if available, otherwise use empty object
// Empty object causes isMessagesJsonFormat() to return false, so the template
// is treated as plain text (correct for SDK text prompts without metadata)
const metadata = rawPrompt.version.metadata ?? {};
const promptVersion: PromptVersion = {
id: rawPrompt.version.id,
template: normalizeTemplate(rawPrompt.version.template),
metadata,
commit: rawPrompt.version.commit ?? "",
prompt_id: rawPrompt.id,
created_at: date, // We don't have this in raw data, using current time
};
return {
id: rawPrompt.id,
name: rawPrompt.name,
description: "", // We don't have this in raw data
last_updated_at: date, // We don't have this in raw data
created_at: date, // We don't have this in raw data
version_count: 1, // Assuming single version
tags: [], // We don't have this in raw data
template_structure: rawPrompt.template_structure,
latest_version: promptVersion,
};
};
const PromptsTab: React.FunctionComponent<PromptsTabProps> = ({
data,
search,
}) => {
const {
permissions: { canUsePlayground },
} = usePermissions();
const rawPrompts = get(
data.metadata as Record<string, unknown>,
"opik_prompts",
null,
) as PromptLibraryMetadata[] | null;
const workspaceName = useAppStore((state) => state.activeWorkspaceName);
const showOptimizerPrompts = useIsFeatureEnabled(
FeatureToggleKeys.OPTIMIZATION_STUDIO_ENABLED,
);
const prompts = useMemo(() => {
if (!showOptimizerPrompts) return [];
if (Array.isArray(rawPrompts) && rawPrompts.length > 0) {
return (rawPrompts as PromptLibraryMetadata[]).map(
convertRawPromptToPromptWithLatestVersion,
);
}
return [];
}, [rawPrompts, showOptimizerPrompts]);
const renderPrompts = () => {
if (!prompts || prompts.length === 0 || !rawPrompts) return null;
return prompts.map((promptInfo: PromptWithLatestVersion, index: number) => {
const promptName = promptInfo?.name || `Prompt ${index + 1}`;
const rawTemplate = rawPrompts[index]?.version?.template;
const commitHash = promptInfo?.latest_version?.commit;
const promptId = promptInfo?.id;
return (
<AccordionItem key={index} value={`prompt-${index}`}>
<AccordionTrigger>
<div className="flex items-center gap-2">
<FileTerminal className="size-4" />
<div className="flex flex-col items-start">
<div className="flex items-center gap-2">
<span>Prompt: {promptName}</span>
{commitHash && (
<div className="flex items-center">
<GitCommitVertical className="size-3 text-muted-slate" />
<span className="text-muted-slate">
{commitHash.substring(0, 8)}
</span>
</div>
)}
</div>
</div>
</div>
</AccordionTrigger>
<AccordionContent className="px-3">
<PromptContentView
template={rawTemplate ?? promptInfo?.latest_version?.template}
promptId={promptId}
activeVersionId={rawPrompts[index]?.version?.id}
workspaceName={workspaceName}
search={search}
templateStructure={rawPrompts[index]?.template_structure}
playgroundButton={
canUsePlayground ? (
<TryInPlaygroundButton
prompt={promptInfo}
ButtonComponent={CustomUseInPlaygroundButton}
/>
) : null
}
/>
</AccordionContent>
</AccordionItem>
);
});
};
return (
<Accordion type="multiple" className="w-full" defaultValue={["prompt-0"]}>
{renderPrompts()}
</Accordion>
);
};
export default PromptsTab;