发布

  • [OPIK-4935] [BE] feat(api): add project_name scoping to experiment stream endpoints (#5748)

    frostbyte_neo 发布于 2026-03-20 10:25:28 +00:00

    • [OPIK-4935] [BE] feat(api): add project_name and project_id scoping to prompt version endpoints

    Add project_name and project_id fields to POST /v1/private/prompts/versions/retrieve
    and POST /v1/private/prompts/versions, allowing callers to scope prompt lookups
    and creation to a specific project.

    • PromptVersionRetrieve: add optional project_name (filters lookup to given project)
    • CreatePromptVersion: add optional project_id (takes precedence) and project_name
    • PromptService: extract resolveProjectId() helper; use strict DAO lookup in
      retrievePromptVersion to prevent fallback to workspace-level when project_name
      is explicitly provided; validate project_id existence when supplied
    • PromptResourceTest: update all PromptVersionRetrieve call sites to use builder,
      add project_name scoping and validation tests

    Implements OPIK-4935

    • fix(prompts): throw NotFoundException when project_name is provided but not found in retrieve

    • fix(prompt): restore workspace-level fallback in retrievePromptVersion

    Use the private findByName helper (which already handles the
    project → workspace fallback) instead of calling promptDAO.findByName
    directly, so retrieval behaves consistently with the creation path.

    • test(prompt): update retrieve fallback test to match workspace-wide fallback design

    When the project-level lookup misses, retrievePromptVersion falls back
    to a workspace-wide search. Updated the test to assert 200 (found via
    fallback) instead of 404.

    • test(prompt): add missing retrieve scenarios for project-scope fallback
    • workspace-level prompt found when projectName is specified (fallback)
    • 404 when projectName does not exist in the workspace
    • [OPIK-4981] [BE] Fall back to workspace-wide in retrievePromptVersion when project not found

    When projectName is provided but does not resolve to an existing project,
    pass null as projectId so the lookup falls through to workspace-wide search
    instead of throwing 404.

    • [OPIK-4935] [BE] feat(api): add project_name scoping to experiment stream endpoints

    Add project_name filtering support to POST /experiments/stream and
    POST /experiments/items/stream, allowing callers to scope results to
    a specific project. When project_name is provided and the project does
    not exist, an empty stream is returned. When absent, the endpoints
    continue to return workspace-wide results.

    • ExperimentStreamRequest: add projectName field
    • ExperimentService: resolve projectName → projectId and pass to DAO filter
    • ExperimentItemStreamRequest: add projectName field
    • ExperimentItemSearchCriteria: add projectId field
    • ExperimentItemService: resolve projectName → projectId via reactive
      Mono.deferContextual; short-circuit to empty Flux when project not found
    • ExperimentItemDAO: add <if(project_id)> conditional to STREAM SQL for
      both experiment_items_ids and experiment_item_aggregates_final CTEs
    • ExperimentsResource: wire projectName through to service/criteria
    • ExperimentsResourceTest: add 4 new tests covering project-scoped and
      cross-project isolation for both stream endpoints

    Implements OPIK-4935

    • fix(experiment-items): eliminate duplicate project DB lookup and extract shared resolver
    • Add ProjectService.resolveProjectId(projectName) reactive helper to centralize
      project name resolution across services
    • Fix ExperimentItemService.getExperimentItems: pass resolved projectId into criteria
      instead of ignoring the result of resolveProjectId (was causing a second DB call)
    • Fix ExperimentItemService.findExperimentIdsAndGetItems: use criteria.projectId()
      with the new ExperimentService.findByName(name, UUID) overload, eliminating the
      duplicate findProjectIdByName call
    • Simplify ExperimentService.getProjectByName to delegate to the shared helper
    • Add ExperimentService.findByName(String name, UUID projectId) overload for direct
      UUID-based filtering without triggering an additional project lookup
    • fix(test): create experiments with projectId to match FIND_BY_NAME filter

    The test streamByExperimentNameAndProjectName_whenProjectExists_thenReturnOnlyItemsForThatProject
    was creating experiments without a project_id, which defaults to '' in ClickHouse.
    The FIND_BY_NAME query filters by experiments.project_id, so experiments with '' would
    never match the resolved projectId UUID, returning empty results.

    Fix: set projectId on each experiment at creation time so the column is populated correctly.

    下载附件