发布

  • [OPIK-6456] [BE] feat: add prompt masks for non-destructive prompt resolution (#6731)

    frostbyte_neo 发布于 2026-05-19 08:26:31 +00:00

    • [OPIK-6456] [BE] feat: add prompt masks for non-destructive prompt resolution

    Add version_type ENUM('prompt_version','mask') discriminator column on
    prompt_versions, defaulting existing rows to 'prompt_version'. This is
    the schema foundation for mask overlays: masks live in the same table
    as regular prompt versions but are filtered out of latest_version and
    version_count queries, and selectable via mask_id at resolution time.

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • feat(prompts): add PromptVersionType enum and versionType field

    Introduces the PROMPT_VERSION/MASK discriminator at the API layer.
    versionType defaults to PROMPT_VERSION so existing clients are
    unaffected; mask creation will set it to MASK on the embedded
    PromptVersion in CreatePromptVersion.

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • feat(prompts): filter masks from list/count queries and support mask_id resolution in findById
    • prompt_versions.version_type='prompt_version' filters added to:
      • latest_version and version_count subqueries in PromptDAO findById/find/findByIds/count
      • PromptDAO.findByCommit and findPromptsByCommits (commits are prompt-version-only)
      • PromptVersionDAO.find/findCount when listing by prompt_id (id-based lookups still
        return any type so masks remain reachable by id)
      • PromptVersionDAO.findByCommit
    • PromptDAO.findById gains an optional mask_id that, when present, populates
      requested_version with that version row (service validates it is actually a mask)
    • INSERT in PromptVersionDAO.save writes the new version_type column
    • PromptVersionColumnMapper reads version_type from JSON_OBJECT payloads with a
      PROMPT_VERSION fallback for older serialized rows

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • feat(prompts): mask-aware getById and bulk retrieveVersionsByIds in service
    • getById(UUID, UUID maskId): delegates to PromptDAO.findById with the
      optional mask_id. When a mask_id is supplied and no row matches for
      the given prompt, throws NotFoundException so callers see a clean 404
      instead of a Prompt with a null requestedVersion.
    • retrieveVersionsByIds(List): bulk version lookup powering the
      upcoming POST /v1/private/prompts/retrieve endpoint. Returns versions
      in whatever order PromptVersionDAO produces (id DESC); missing ids
      are dropped from the response.
    • Existing getById(UUID) delegates to the new overload with maskId=null,
      so all current callers keep their behavior.
    • Variable enrichment factored into enrichWithVariables() and applied
      to both latestVersion and requestedVersion on the resolution path.

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • feat(prompts): mask_id query param on GET /prompts/{id} and POST /prompts/retrieve
    • GET /v1/private/prompts/{id} accepts an optional mask_id query param.
      When set, the response Prompt has requestedVersion populated with the
      matching mask version (404 if no such version belongs to this prompt).
    • POST /v1/private/prompts/retrieve accepts { ids: [...] } and returns
      List. Powers the FE flow that resolves multiple mask
      overlays in a single round-trip.
    • PromptVersionIdsRequest validates 1..1000 non-null UUIDs.

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • feat(prompts): suppress PROMPT_COMMITTED alerts and lastUpdatedAt bump on mask saves

    Masks are non-destructive overlays, not real commits. They should not
    trigger PROMPT_COMMITTED alert subscribers and should not move the
    parent prompts last_updated_at, which the UI surfaces as recent prompt
    activity. Both side effects are now gated on versionType != MASK;
    regular prompt_version saves are unchanged.

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • test(prompts): cover mask creation, isolation, mask_id resolution, bulk retrieve

    New PromptMasks nested class in PromptResourceTest:

    • mask creation via POST /prompts/versions with version_type=mask
    • masks excluded from latestVersion and versionCount on GET /prompts/{id}
    • masks excluded from GET /prompts/{id}/versions and from commit-based
      lookups (/by-commit and /retrieve-by-commits)
    • GET /prompts/{id}?mask_id=... populates requestedVersion with the mask
      while keeping latestVersion pointed at the latest real version
    • 404 when mask_id is unknown or belongs to a different prompt
    • POST /prompts/retrieve returns versions by id and rejects empty bodies
    • creating a mask does not bump the parent prompts lastUpdatedAt

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • remove unused import

    • feat(local-runners): carry multiple prompt masks per job via prompt_masks

    Extends CreateLocalRunnerJobRequest and LocalRunnerJob with promptMasks,
    a Map<promptId, maskId> that lets a local-runner job overlay masks on
    several prompts in a single run. The existing single maskId field stays
    in place but is marked @Deprecated for both DTOs.

    EndpointJobServiceImpl persists prompt_masks as JSON on the Redis job
    hash and restores it via parsePromptMasks on every job read path
    (nextJob, getJob, listJobs).

    LocalRunnersResourceTest covers create + claim round-trips for the new
    field and that promptMasks is null when not provided.

    Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

    • bump migration version

    • address comments

    • bump migration number

    下载附件