-
[OPIK-6457] [FE] feat: prompts UX improvements across playground, traces, and library (#6771)
发布于
2026-05-27 13:18:32 +00:00 -
initial commit;
-
[OPIK-6457] [FE] feat: prompts UX improvements across playground, traces, and library
- New cascading prompt+version selector (PromptLibraryMenu) used in the chat playground
- Per-version loading: PlaygroundPrompt now tracks loadedChatPromptVersionId so a picked version persists across reloads; useLoadChatPrompt and useHydratePromptMetadata honor it
- Sidebar create-prompt flow (CreatePromptSheet) launched from a "+ Prompt" dropdown that picks text or chat
- PromptPage shows skeleton placeholders while versions / active version load
- New Prompts tab in the trace details panel, rendered as collapsible PromptCards with pretty/raw toggle, copy, and an "Open in playground" action guarded by ConfirmDialog
- Agent playground Configuration tab now lists all project prompts as editable cards, each with a version dropdown, inline edit, and save-as-new-version
- Centralized pickHighestStage in utils/agent-configurations.ts; AutoResizeTextarea accepts a placeholder
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
-
update prompts, prompt, prompt playground, and traces view;
-
cleanup + baz review fixes for prompts UX branch
- extract DeployToEnvironmentMenu out of PromptTab (728->584 lines) and
gate it behind canConfigureWorkspaceSettings - factor resolveEnvironmentColor + getContrastingTextColor into shared
helpers.ts so EnvironmentLabel and EnvironmentBadge stop duplicating - pass parent Prompt to CompactLoadedPrompt so it skips the redundant
usePromptById fetch when the list already has it - PromptCard: pass inferred isChatPrompt-derived templateStructure to
loadPlayground; only set activeVersionId in the trace link when present - AgentRunnerPromptCard: gate "Save as new version" by canCreatePrompts
- useLoadChatPrompt: fall back to a single user message when the chat
template isn't a JSON array, instead of silently dropping the load - useHydratePromptMetadata: when an explicit version id was requested but
the fetch failed, return undefined rather than comparing to latest_version - TraceDataViewer: normalize legacy traceTab=configuration to prompts/details
- LLMPromptMessageActions: use hasContent (trimmed text predicate) for
saveDisabled so [] and whitespace messages no longer enable Save - AgentRunnerPromptCard: memoize versions to clear pre-existing
react-hooks/exhaustive-deps warning
Also updates .agents/skills/opik-frontend skills with the new patterns.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- extract version-stage helpers out of agent-configurations utils
Move VersionStage enum (was AgentConfigurationBasicStage), pickHighestStage,
isProdTag, isBasicStage, sortTags into a new utils/version-stages.ts. The
prompt-version UI (PromptTab, PromptCard, LoadedPromptDisplay, PromptLibraryMenu,
StageTag, VersionTagList, AgentRunnerPromptCard) now imports from there.utils/agent-configurations.ts keeps only formatBlueprintValue. Dead exports
(AGENT_CONFIGURATION_METADATA_KEY, AGENT_CONFIGURATION_PROD_ENV_NAME, isStageTag)
removed since nothing else references them.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- small wins: internal sheet reset, memoize metadata, dedup tooltips, plumb diff target
- EditPromptSheet now resets its own draft state on each open via an effect on
the open prop (with a ref to capture latest props). Removed the
editPromptResetKeyRef force-remount hack from PromptTab. - PromptTab: wrap metadataJson in useMemo so JSON.stringify only runs when
activeVersion.metadata changes (Baz #11). - New constants/prompts.ts with PROMPT_UNSAVED_TOOLTIP,
PROMPT_UNSAVED_EXPERIMENT_TOOLTIP, PROMPT_SAVE_AS_CHAT_TOOLTIP. Replaces
duplicated literals across v1 + v2 LLMPromptMessageActions, PlaygroundPrompt,
and OptimizationsNewPromptSection (Baz #14). - ComparePromptVersionDialog accepts initialDiffVersionId; PromptTab tracks the
version clicked in DiffVersionMenu and passes it through so the dialog opens
on the requested diff target instead of always last (Baz #16).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix: clear pre-existing prettier nit in ImproveInPlaygroundButton
Carried over from an earlier branch commit; running npm run lint surfaced
the leftover paren wrapping on a ?? expression.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(compare): use active version as base when comparing from DiffVersionMenu
Previously the dialog seeded baseVersion to first(versionOptions) (v1) on
every open, so picking a target from DiffVersionMenu while viewing v5
always rendered "v1 → picked" instead of involving v5. Add
initialBaseVersionId; when both base + diff are anchored by the caller,
order them chronologically so the diff reads from-old → to-new. Falls back
to v1 → vN when no anchor is passed (CommitsActionsPanel's flow stays the
same).Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(compare): the picked version is the base, active is the diff
Correct mental model: user on v5 picks v3 from DiffVersionMenu meaning
"compare against v3" — v3 is the anchor (base), v5 is what they're
currently inspecting (diff). Reads as "Compare v3 → v5".Drop the chronological ordering from the previous commit and pass the
picked id as initialBaseVersionId / effectiveVersionId as
initialDiffVersionId. Rename the PromptTab state from diffTargetVersionId
to compareAgainstVersionId so the intent matches the wiring.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(playground): pin loaded chat prompt to picked version
useLoadPlayground's createPromptFromContent set loadedChatPromptId but
not loadedChatPromptVersionId for CHAT prompts. On the playground page,
useLoadChatPrompt then fell back to chatPromptData.latest_version.id and
refetched, overwriting the messages the caller passed. Result: opening
an older version with "Use prompt" silently loaded the latest version
instead.Persist promptVersionId on the new prompt so the playground hydrates the
exact version that was picked.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(playground): always load the picked version, not stale placeholder
usePromptVersionById on PromptTab uses placeholderData: keepPreviousData,
so activeVersion keeps the previous version's data while the newly
picked versionId is being fetched. The toolbar stays interactive during
that window, so clicking "Use prompt" or "Open in playground" right after
selecting v3 in the timeline read activeVersion.id = v5 and shipped the
latest version's content + id to the playground.Add a guard in handleLoadIntoPlayground: if activeVersion.id doesn't
match effectiveVersionId (the URL-anchored selection), fetch the version
imperatively via useFetchPromptVersion before calling loadPlayground.
This fixes both TEXT and CHAT prompts — the playground now always
hydrates from the version the user actually picked.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
-
[OPIK-6457]: agent playground;
-
bug fixes;
-
fix(prompt-diff): normalize chat templates and split side-by-side rendering
Re-serialize chat templates to a stable pretty-printed shape before diffing
so payloads stored with different whitespace align, preserve indentation in
TextDiff, and add a side prop so the base column shows removals only and
the diff column shows additions only.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- chore(prompts): hide Deploy to environment button on prompt page
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
-
improvements;
-
prompts: misc UX fixes and compare dialog cleanup
- Empty-state cards: use a single openCreate state so the chosen template
structure (text vs chat) is always tied to the click that opened the
sheet. - Chat prompt creation requires at least one non-empty message.
- ExperimentsTab empty state: short instruction + docs link explaining how
to run an evaluation against the prompt. - ComparePromptVersionDialog: add Messages/Raw view toggle for chat
diffs (defaults to Messages) and extract MetadataColumn, MediaRow,
parseChatTemplate, and stringifyMetadata to dedupe the JSX.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
-
form improvements
-
design improvements;
-
improve the view of difference;
-
fix a bug with suites;
-
eslint issues;
-
code improvements
-
baz comments;
-
eslint issues;
-
design comments;
-
baz comments;
-
eslint issues;
-
update the gap;
-
[OPIK-6653] [BE][FE] fix: attach opik_prompts metadata to playground experiment traces (#6838)
-
fix(playground): attach opik_prompts metadata to experiment traces
When a playground experiment runs against a dataset, traces are written
by the backend rather than by the FE SDK path, so theopik_prompts
metadata key that the trace view's Prompts tab keys off of was never
set — the linked prompt was invisible in traces.FE: collect prompt_versions from both chat-level (loadedChatPrompt*) and
message-level (message.promptId/promptVersionId) links, and send actual
version ids (the previous payload sent the prompt id where a version id
was expected).BE: thread prompt_versions through ExperimentItemToProcess and
PersistenceContext, then resolve them via PromptService.findVersionByIds
in ExperimentTracePersistence and write the resulting array under the
opik_promptsmetadata key in the same shape the Python SDK uses.
Failures to resolve fall back to omitting the key rather than failing
the trace write.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- perf(playground): resolve prompt versions once per experiment, not per trace
Address PR feedback: ExperimentTracePersistence was calling
promptService.findVersionByIds for every dataset item, so a 1000-item
experiment hit the prompt store 1000× with the same version ids. Move
the lookup up into ExperimentExecutionService where it happens exactly
once per request, build the opik_prompts ArrayNode per variant up
front, and pass it through ExperimentItemToProcess/PersistenceContext
ready to be set on trace metadata. ExperimentTracePersistence no longer
depends on PromptService.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(playground): make opik_prompts resolution tolerant of missing version ids
Address PR feedback:
- PromptService.findVersionByIds is now lenient: it returns whatever
was found in the workspace instead of erroring when a subset of ids
is missing. The one strict caller (ExperimentService.validatePromptVersion)
inlines the size check itself. This keeps the API surface to a single
method while letting opik_prompts resolution survive stale links. - ExperimentExecutionService.resolveOpikPromptsByVariant no longer
null-arrays every variant when one version id is unresolvable; only
the missing entries are dropped via the existing skip in
buildOpikPromptsArray. The error-path warning now carries datasetName,
datasetId, and versionHash for correlation. - Add OpikPromptsResolution test class covering: multi-variant happy
path, no-links short-circuit, partial-miss (sibling variants
preserved), and full lookup failure.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- revert: restore strict findVersionByIds, rely on upstream validation
Prompt version ids are already validated when the experiment is created
(ExperimentService.processExperimentCreation -> validatePromptVersion),
so by the time ExperimentExecutionService.resolveOpikPromptsByVariant
runs they are guaranteed to exist. Relaxing findVersionByIds was
unnecessary and changed an API contract for callers unrelated to this
work. Drop the partial-miss test from the OpikPromptsResolution suite;
the defensive onErrorResume in resolveOpikPromptsByVariant remains so a
transient DB error during the lookup just drops opik_prompts metadata
instead of failing the experiment.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- refactor(playground): introduce OpikPromptEntry typed DTO for opik_prompts
Replace the raw ArrayNode flowing through ExperimentItemToProcess and
PersistenceContext with a typed record OpikPromptEntry (plus inner
Version). The wire shape is unchanged: id, name, template_structure,
version: { id, template, commit, version_number, metadata }. The
template field is JsonNode so chat-prompt templates serialize as parsed
arrays/objects (matching the Python SDK output), not escaped JSON strings.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- fix(playground): branch template node by template_structure
toTemplateNode wraps TEXT prompt templates in a TextNode unchanged and
parses JSON only for CHAT prompts (falling back to TextNode if the chat
template is not valid JSON). Previously TEXT templates that happen to be
valid JSON (e.g. "42", "true") were eagerly parsed into a primitive
node, breaking the SDK wire contract. Add three OpikPromptsResolution
tests covering TEXT-as-string, CHAT-as-array, and CHAT-fallback paths,
and switch hardcoded literals in the existing opik_prompts tests to
RandomStringUtils-generated values.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com
-
comments;
-
error message improvement;
-
long names;
-
bug fixes and code improvements;
Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com
Co-authored-by: Petro Tiurin 2856640+petrotiurin@users.noreply.github.com下载附件
-