Member Junction
    Preparing search index...

    Runs text-to-speech on TTS models (BaseTextToSpeech drivers). It does for a speech call what AIPromptRunner does for a chat call: selects a model from the carrier prompt's bindings (or the pinned ModelID), resolves credentials, fails over, and writes an MJ: AI Prompt Runs row.

    The row never holds audio. Messages records the text, the voice and the character count, and Result the audio's format, size and, when the driver reported it, duration. Usage is the driver's when it reports a quantity; otherwise the characters sent are counted in the Characters measure. No price unit type prices Characters yet, so such a run is left uncosted, with a logged reason, rather than priced wrong. The runner never sets a cost itself.

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    _metadata: Metadata
    _promptRunQueue: BaseEntitySaveQueue = ...
    _provider: IMetadataProvider = null
    DEFAULT_PROMPT_NAME: "Default Text To Speech" = 'Default Text To Speech'

    The carrier prompt used when the caller names none.

    Accessors

    • get DefaultPromptTimeoutMS(): number

      Engine-level default model-call timeout, in milliseconds, applied when the caller supplies no AIPromptParams.timeoutMS. undefined (the default) means NO implicit bound — a prompt run with neither a timeout nor a cancellation token stays unbounded, exactly as before, so this change is behavior-preserving for existing callers.

      Subclasses (or a host application's runner subclass) can override this to impose a global safety ceiling on every prompt call.

      Returns number

    Methods

    • The error for a model call the caller cancelled. It is classified Cancelled — Fatal and not eligible for failover — so ErrorAnalyzer, the failover loop and the validation retries all stop on it rather than treating it as an unknown model error.

      Parameters

      • Optionalmessage: string

        The message to keep, when a driver already reported the cancellation.

      Returns Error & { errorInfo: AIErrorInfo }

    • Builds a unified, ordered list of model-vendor candidates based on all selection criteria. Uses a 3-phase approach to properly handle SelectionStrategy='Specific' with AIPromptModel priorities.

      Phase 1: Handle explicit model ID (highest priority) Phase 2: Check if SelectionStrategy='Specific' with AIPromptModel entries - use ONLY those with AIPromptModel priorities Phase 3: Use general selection strategy (fallback) - blended priorities from legacy behavior

      Parameters

      • prompt: MJAIPromptEntityExtended

        The AI prompt with selection criteria

      • OptionalexplicitModelId: string

        Explicitly specified model ID (highest priority)

      • OptionalconfigurationId: string

        Configuration ID for filtering

      • OptionalpreferredVendorId: string

        Preferred vendor ID

      • Optionalverbose: boolean

      Returns ModelVendorCandidate[]

      Ordered array of model-vendor candidates (highest priority first)

    • Calculates the delay before the next failover attempt.

      Parameters

      • attemptNumber: number

        The current attempt number (1-based)

      • baseDelaySeconds: number

        The base delay in seconds from configuration

      Returns number

      Delay in milliseconds before the next attempt

      Implements exponential backoff with jitter by default. The delay increases exponentially with each attempt and includes random jitter to prevent thundering herd problems. Override this method to implement custom delay logic.

    • Composes the caller-supplied cancellation token with the resolved model-call timeout into a single AbortSignal that bounds one model call. NEITHER bound is discarded:

      • caller token only → the caller's signal is used directly (behavior unchanged)
      • timeout only → an internal controller aborts after the timeout elapses
      • both → an internal controller relays the caller's abort AND fires on timeout; whichever happens first wins
      • neither → Signal is undefined and the call runs unbounded (legacy behavior)

      Implemented with an AbortController + relay listener rather than AbortSignal.any() so it works on Node 18 (where AbortSignal.any does not exist — it landed in Node 20.3).

      Parameters

      Returns ExecutionBound

    • A copy of the caller's params without the runner's own fields, so a driver never sees the user or the keys. The caller's CancellationToken is replaced by signal, the call's bound (the caller's token composed with the timeout), which the driver forwards to its request.

      Type Parameters

      • T

      Parameters

      • params: T & AIMediaRunOptions

        The caller's params.

      • signal: AbortSignal

        The bound's signal for this driver call, or undefined when the call is unbounded.

      Returns T

    • Finalizes a prompt-run record in memory immediately AND queues a fire-and-forget UPDATE on _promptRunQueue that re-applies the finalized state after any in-flight 'Running' INSERT and its finalizeSave reload complete.

      Applying the completion fields synchronously in memory ensures callers that inspect result.promptRun right after ExecutePrompt (such as BaseAgent.calculateTokenStats() reading TokensPromptRollup, TokensCompletionRollup, TotalCost, and Status) see the finalized values immediately without blocking on the database round-trip, while re-applying the captured snapshot inside _promptRunQueue.Update(promptRun, ...) guarantees an in-flight INSERT reload can never revert the persisted row back to 'Running'.

      In order, it sets: the completion timing (CompletedAt, ExecutionTimeMS); the outcome (Success, and Status = 'Completed' or 'Failed' from it); any pending failover fields; the subclass's result fields (applyResultFields, invoked once); and finally the token rollups and TotalCost.

      Parameters

      • promptRun: MJAIPromptRunEntityExtended
      • success: boolean

        Whether the call succeeded, as the runner judges it (the chat runner also requires its output to pass validation).

      • endTime: Date
      • executionTimeMS: number
      • applyResultFields: (promptRun: MJAIPromptRunEntityExtended) => void

        Sets the runner's own result columns. It can read the timing and outcome already set, and may refine them (for example ErrorDetails or Status = 'Cancelled'). It must be synchronous.

      Returns Promise<void>

    • Awaits all in-flight MJAIPromptRunEntityExtended INSERT and UPDATE operations queued on this runner's internal BaseEntitySaveQueue (_promptRunQueue) and clears the in-flight parent lookup table.

      Normal intra-step prompt execution is non-blocking (fire-and-forget); callers that own the outer lifecycle (such as BaseAgent at run completion, failure, cancellation, or compaction) call FlushPendingSaves() to guarantee every AIPromptRun row is durably settled before returning.

      Returns Promise<void>

    • Resolves the per-model-call timeout: the caller's AIPromptParams.timeoutMS, else the runner's DefaultPromptTimeoutMS. Non-positive / non-numeric values mean "no timeout".

      The bound is applied PER MODEL CALL (not per prompt execution), which mirrors the parallel path's existing taskTimeoutMS semantics: each failover candidate / validation retry gets a fresh budget rather than sharing one wall-clock window.

      NOTE (issue #3064): there is deliberately NO prompt-entity source here yet — the AIPrompt table has no TimeoutMS column today. Once a migration adds one and CodeGen regenerates the entity, this becomes prompt.TimeoutMS ?? params.timeoutMS ?? this.DefaultPromptTimeoutMS and every bound below starts honoring the per-prompt configuration with no other change.

      Parameters

      Returns number

    • Checks if credentials are available for a given model-vendor combination. This is a pre-flight check used during model selection to determine which candidates have valid authentication configured.

      Checks the credential hierarchy:

      1. Per-request override: params.credentialId
      2. PromptModel bindings: AICredentialBinding WHERE BindingType='PromptModel'
      3. ModelVendor bindings: AICredentialBinding WHERE BindingType='ModelVendor'
      4. Vendor bindings: AICredentialBinding WHERE BindingType='Vendor'
      5. Type-based default: Credential.IsDefault=1 matching AIVendor.CredentialTypeID
      6. Legacy: params.apiKeys[] array
      7. Legacy: AI_VENDOR_API_KEY__ environment variables

      Each tier counts only if CredentialScopeAllows the run's scope to use its source: under 'RuntimeOnly' only 1 and 6 count, so a candidate the caller has no key for is unavailable — which is what keeps failover on the caller's keys.

      Parameters

      • driverClass: string

        The driver class name (e.g., 'OpenAILLM')

      • promptId: string

        The prompt ID for looking up AIPromptModel bindings

      • modelId: string

        The model ID for looking up AIPromptModel and AIModelVendor bindings

      • vendorId: string

        The vendor ID for looking up AIModelVendor and AIVendor bindings

      • Optionalparams: AIPromptParams

        The prompt execution parameters

      Returns boolean

      true if credentials are available, false otherwise

    • Logs a failover attempt for tracking and debugging.

      Parameters

      • promptId: string

        The ID of the prompt being executed

      • attempt: FailoverAttempt

        The failover attempt details

      • willRetry: boolean

        Whether another attempt will be made

      Returns void

      This method logs detailed information about each failover attempt to help with debugging and monitoring. Override this method to implement custom logging or integrate with external monitoring systems.

    • Resolves credentials for AI model execution using a hierarchical resolution system.

      Resolution priority (highest to lowest):

      1. Per-request override: params.credentialId
      2. Prompt-Model specific: AIPromptModel.CredentialID
      3. Model-Vendor specific: AIModelVendor.CredentialID
      4. Vendor default: AIVendor.CredentialID
      5. Legacy: params.apiKeys[] array
      6. Legacy: AI_VENDOR_API_KEY__ environment variables

      IMPORTANT: When ANY credential ID is found (priorities 1-4), the system uses the Credentials path and ignores legacy methods (priorities 5-6).

      Each tier is consulted only if CredentialScopeAllows the run's AIPromptParams.CredentialScope to use its source. Under 'RuntimeOnly' that leaves priority 1 and the apiKeys entry for this driver class; bindings, the vendor default and the environment are skipped.

      Parameters

      • driverClass: string

        The driver class name (e.g., 'OpenAILLM')

      • promptId: string

        The prompt ID for looking up AIPromptModel credentials

      • modelId: string

        The model ID for looking up AIPromptModel and AIModelVendor credentials

      • vendorId: string

        The vendor ID for looking up AIModelVendor and AIVendor credentials

      • params: AIPromptParams

        The prompt execution parameters containing contextUser and optional credentialId

      Returns Promise<string>

      The API key/configuration string to pass to the LLM constructor

    • The usage to record for one call: the driver's when it reports a quantity (tokens, or units in a measure), otherwise the runner's own count, which keeps any cost the driver gave. With neither, the driver's usage (possibly undefined) is returned, and nothing is invented.

      A runner counts what it can see without the driver: the images returned, or the characters it sent. The driver's figure wins because it is the vendor's own measure.

      Parameters

      • reported: ModelUsage

        The usage the driver returned, if any.

      • counted: ModelUsage

        The runner's own count as ModelUsage.ForMedia, or undefined when it has none.

      Returns ModelUsage

    • Selects candidate models for failover based on the strategy and current failure.

      Parameters

      • currentModel: MJAIModelEntityExtended

        The model that just failed

      • currentVendorId: string

        The vendor ID that just failed

      • strategy: "SameModelDifferentVendor" | "NextBestModel" | "PowerRank" | "None"

        The failover strategy to use

      • modelStrategy: "PreferSameModel" | "PreferDifferentModel" | "RequireSameModel"

        The model selection preference

      • allCandidates: ModelVendorCandidate[]

        All available model-vendor candidates

      • attemptHistory: FailoverAttempt[]

        History of previous failover attempts

      Returns ModelVendorCandidate[]

      Array of candidates sorted by priority (highest first)

      This method implements different strategies for selecting failover candidates:

      • SameModelDifferentVendor: Try the same model with different vendors
      • NextBestModel: Try different models in order of preference
      • PowerRank: Use the global power ranking of models

      Override this method to implement custom candidate selection logic.

    • Determines whether a failover attempt should be made based on the error and configuration.

      Parameters

      • error: Error

        The error that occurred during execution

      • config: FailoverConfiguration

        The failover configuration

      • attemptNumber: number

        The current attempt number (1-based)

      Returns boolean

      True if failover should be attempted, false otherwise

      This method uses the ErrorAnalyzer to classify errors and determine if they are eligible for failover based on the configured error scope. Override this method to implement custom failover decision logic.

    • Awaits all in-flight prompt-run saves queued by this runner instance. The normal execution path does NOT call this — prompt-run persistence is intentionally fire-and-forget. Exposed for tests and for callers that need the AIPromptRun rows durably written before proceeding.

      Returns Promise<void>