发布

  • [OPIK-5937] [SDK] feat: allow direct Prompt and ChatPrompt instantiation (#6317)

    frostbyte_neo 发布于 2026-04-20 08:06:09 +00:00

    • [OPIK-5937] [SDK] feat: allow direct Prompt and ChatPrompt instantiation

    Add global client singleton (getGlobalClient/setGlobalClient/resetGlobalClient)
    mirroring Python's pattern. Prompt and ChatPrompt now accept an optional opik
    parameter (deprecated) and auto-sync with the backend on construction via the
    global client when no explicit client is provided.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • fix: guard _performSync against unsynced returns and recursive sync loop
    • Add skipAutoSync flag to BasePromptData so Client.ts unsynced fallbacks
      do not re-trigger _performSync (prevents infinite recursion when
      createPrompt() fails and returns a new unsynced Prompt).
    • Extract shared sync logic into BasePrompt._syncViaCreate: only calls
      updateSyncState when the returned instance has synced===true and all
      required fields (id, versionId, commit) present; otherwise logs a
      warning and leaves _synced false so requireSynced() cannot pass with
      undefined IDs.
    • Simplify Prompt._performSync and ChatPrompt._performSync to delegate
      to _syncViaCreate.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • refactor(prompt): remove fallback unsynced instance from createPrompt/createChatPrompt

    API errors now propagate to the caller instead of returning an unsynced
    local-only instance, matching Python SDK behaviour. Removes skipAutoSync
    flag which was only needed to prevent infinite recursion from that fallback.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • test(prompt): add direct instantiation tests and fix deprecation overloads
    • Use constructor overloads so @deprecated only triggers when opik arg is passed
    • Add unit tests covering background sync, ready(), format(), and error resilience
    • Fix test mocks to use Object.defineProperty instead of private field access
    • Remove unused OpikApiTimeoutError import from Client.ts

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • test(client): update createPrompt/createChatPrompt error tests to expect throws

    Removes tests that asserted unsynced fallback instances were returned on
    OpikApiError/OpikApiTimeoutError — that behaviour no longer exists.
    Replaces them with tests that assert the errors propagate to the caller.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • refactor(prompt): use opik presence to guard auto-sync, restore fallback on API error

    Auto-sync in the constructor now fires only when no explicit opik client
    is passed (direct instantiation). When opik is passed (internal client
    calls and backward-compat usage), no auto-sync fires — the client manages
    the lifecycle. This naturally prevents recursion without a skipAutoSync flag.

    createPrompt/createChatPrompt restore the fallback: OpikApiError and
    OpikApiTimeoutError return a local-only unsynced instance instead of
    throwing, matching the original behaviour.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • refactor(client): move fallback catch into createPromptInternal via createUnsyncedInstance param

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • fix(prompt): propagate projectName through updateSyncState after background sync

    Direct new Prompt/ChatPrompt instances stayed projectName === undefined after
    a successful backend sync because updateSyncState only updated id/versionId/
    commit/changeDescription. projectName is now a private-backed field updated
    alongside the other sync state.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • fix(agent-config): defer trace metadata injection until unsynced prompts are ready

    When a directly-instantiated Prompt/ChatPrompt (still background-syncing)
    is used as a config field and the config is accessed before ready()
    resolves, metadata injection is now deferred until all pending prompt
    syncs complete, using the already-captured trace context.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • feat(prompt): add sync timeout; inject fallback metadata on agent-config timeout
    • PROMPT_SYNC_TIMEOUT_MS (5s) in BasePrompt races background sync;
      on timeout ready() rejects so callers can detect the failure
    • AGENT_CONFIG_PROMPT_READY_TIMEOUT_MS (5s) in agent-config Config;
      deferred metadata injection fires after timeout using fallback —
      unsynced prompt fields get undefined commit (same as API error path)

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • feat(prompt): await prompt sync at getOrCreateConfig time; minimal injection

    Before hitting the backend in getOrCreateConfig, all unsynced BasePrompt
    values in fallback are awaited. If they do not sync within
    AGENT_CONFIG_PROMPT_READY_TIMEOUT_MS (5s), the call is treated as a fetch
    failure and fallback values are used immediately without a backend call.
    injectTraceMetadata is now fully synchronous — unsynced prompts in
    metadata get undefined commit (same as the fallback path).

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • fix(prompt): resolve ready() on sync timeout instead of rejecting

    Timeout in _syncViaCreate now logs a warning and returns (same as API
    error path) rather than throwing. ready() always resolves; the prompt
    stays unsynced and can be retried via syncWithBackend().

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • CR

    • fix(agent-config): verify all prompts synced before auto-creating config

    Combine timeout check and sync-state check into _allPromptsSynced().
    After ready() resolves, re-verify that every prompt actually synced
    (commit is populated). If any failed, return fallback config instead
    of serializing broken prompt references into the blueprint.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • Restore comments

    • [OPIK-5937] [SDK] refactor: optimize timeout test and improve sync error messages

    Improvements:

    • Optimize timeout test to use fast fake timers with chunked advancement (18ms vs 5.5s)
    • Add detailed comment explaining Vitest fake timer + Promise.allSettled() edge case
    • Add unhandled rejection protection in _syncViaCreate() to prevent late rejections
    • Update error/warning messages to guide users: await prompt.ready() → syncWithBackend()

    The timeout test now uses chunked advancement (3 x 2000ms) instead of single large advance
    to properly flush microtask queue in Vitest fake timer environment. All 1118 unit tests pass
    in 8.69s total.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • [OPIK-5937] [SDK] refactor: make prompt sync implicit in version operations

    Prompts now automatically handle initialization when accessing version operations like getVersions(), delete(), and updateProperties(). Users no longer need to manually call .ready() before these operations.

    Changes:

    • Updated BasePrompt methods to implicitly await .ready()
    • Replaced requireSynced() with warnIfNotSynced() for graceful degradation
    • Updated documentation to remove all sync implementation details
    • Simplified examples to showcase natural, seamless usage

    This improves user experience by removing unnecessary abstraction leaks about background initialization.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • fix: resolve TypeScript type narrowing in _syncViaCreate

    Explicitly check for undefined result from createPromise when it rejects after timeout, allowing TypeScript to properly narrow the type for subsequent operations.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • refactor: restore hard guard for unsync'd prompts in backend operations

    Replace warnIfNotSynced() with ensureSynced() to throw an error if sync failed.
    This prevents passing undefined prompt IDs to backend API calls and gives users
    clear feedback when initialization failed.

    Users should call syncWithBackend() to retry persisting the prompt.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

    • feat: wait for prompt initialization in evaluate function

    Ensure all prompts linked to experiments are ready before evaluation begins.
    This guarantees prompts are initialized when passed to the experiment.

    Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com


    Co-authored-by: Claude Sonnet 4.6 noreply@anthropic.com

    下载附件