发布

  • [OPIK-6457] [FE] feat: prompts UX improvements across playground, traces, and library (#6771)

    frostbyte_neo 发布于 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 the opik_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_prompts metadata 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

    下载附件