asyncapi: '2.6.0'

info:
  title: llm-orch-svc Async API
  version: 1.0.0
  description: |
    AsyncAPI specification for the LLM Orchestration Service (llm-orch-svc).
    This service is a **producer only** — it publishes Kafka events in CloudEvents 1.0
    format but does not consume any topics.

    All events are partitioned by `tenantId` and wrapped in a CloudEvents 1.0 envelope.
  contact:
    name: EventZR Platform Team
  license:
    name: Proprietary

servers:
  staging:
    url: boot-gpm4u49z.c2.kafka-serverless.us-east-1.amazonaws.com:9098
    protocol: kafka-secure
    description: Amazon MSK Serverless (staging, us-east-1)
    security:
      - saslOauthbearer: []

defaultContentType: application/json

channels:
  eventzr.llm.usage.v1:
    description: Emitted after every successful LLM inference call.
    publish:
      operationId: publishLlmUsage
      summary: LLM usage telemetry event
      message:
        $ref: '#/components/messages/LlmUsageEvent'

  eventzr.llm.quota.low.v1:
    description: Alert fired when a user or tenant credit balance drops below 20%.
    publish:
      operationId: publishQuotaLow
      summary: Quota low-water-mark alert
      message:
        $ref: '#/components/messages/QuotaLowEvent'

  eventzr.llm.budget.exceeded.v1:
    description: Emitted when a budget ceiling (daily, monthly, or per-request) is exceeded.
    publish:
      operationId: publishBudgetExceeded
      summary: Budget exceeded alert
      message:
        $ref: '#/components/messages/BudgetExceededEvent'

  eventzr.llm.provider.outage.v1:
    description: Emitted when a provider circuit breaker changes state (degraded, outage, recovered).
    publish:
      operationId: publishProviderOutage
      summary: Provider health-state change
      message:
        $ref: '#/components/messages/ProviderOutageEvent'

  eventzr.llm.inference.failed.v1:
    description: Emitted when an inference request exhausts all retry attempts across providers.
    publish:
      operationId: publishInferenceFailed
      summary: Inference failure (all retries exhausted)
      message:
        $ref: '#/components/messages/InferenceFailedEvent'

  eventzr.llm.embeddings.generated.v1:
    description: Emitted after embeddings are successfully generated.
    publish:
      operationId: publishEmbeddingsGenerated
      summary: Embeddings generation completed
      message:
        $ref: '#/components/messages/EmbeddingsGeneratedEvent'

  eventzr.llm.semantic-cache.hit.v1:
    description: Emitted when a semantic cache hit avoids a full inference call.
    publish:
      operationId: publishSemanticCacheHit
      summary: Semantic cache hit
      message:
        $ref: '#/components/messages/SemanticCacheHitEvent'

  eventzr.llm.kg.synced.v1:
    description: Emitted after an inference result is synced to the Neptune knowledge graph.
    publish:
      operationId: publishKgSynced
      summary: Knowledge graph sync completed
      message:
        $ref: '#/components/messages/KgSyncedEvent'

components:
  securitySchemes:
    saslOauthbearer:
      type: oauth2
      description: AWS IAM SASL/OAUTHBEARER authentication for Amazon MSK Serverless.
      flows:
        clientCredentials:
          tokenUrl: https://sts.amazonaws.com
          scopes: {}

  schemas:
    # -------------------------------------------------------------------------
    # CloudEvents 1.0 envelope fields (shared across all messages)
    # -------------------------------------------------------------------------
    CloudEventEnvelope:
      type: object
      required:
        - specversion
        - type
        - source
        - id
        - time
        - datacontenttype
        - partitionkey
      properties:
        specversion:
          type: string
          const: '1.0'
          description: CloudEvents specification version.
        type:
          type: string
          description: 'CloudEvents type, e.g. com.eventzr.llm.usage.v1'
        source:
          type: string
          const: llm-orch-svc
          description: Originating service.
        id:
          type: string
          format: uuid
          description: Unique event identifier.
        time:
          type: string
          format: date-time
          description: ISO-8601 timestamp of event creation.
        datacontenttype:
          type: string
          const: application/json
        partitionkey:
          type: string
          format: uuid
          description: Kafka partition key (tenantId).

    # -------------------------------------------------------------------------
    # Event payloads (the `data` field inside the CloudEvents envelope)
    # -------------------------------------------------------------------------
    LlmUsageData:
      type: object
      required:
        - tenantId
        - userId
        - provider
        - model
        - variantKey
        - promptTokens
        - completionTokens
        - totalTokens
        - costUsd
        - latencyMs
        - useCase
        - success
      properties:
        tenantId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
        provider:
          type: string
          description: 'LLM provider identifier (e.g. aws-bedrock, openai, anthropic).'
        model:
          type: string
          description: 'Model identifier (e.g. anthropic.claude-3-sonnet-20240229-v1:0).'
        variantKey:
          type: string
          description: 'Routing variant key used for model selection.'
        promptTokens:
          type: integer
          minimum: 0
        completionTokens:
          type: integer
          minimum: 0
        totalTokens:
          type: integer
          minimum: 0
        costUsd:
          type: number
          format: double
          minimum: 0
        latencyMs:
          type: integer
          minimum: 0
        useCase:
          type: string
          description: 'Application use-case tag (e.g. event-creation, chat, enrichment).'
        success:
          type: boolean

    QuotaLowData:
      type: object
      required:
        - tenantId
        - userId
        - quotaType
        - currentUsage
        - limit
        - percentUsed
      properties:
        tenantId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
        quotaType:
          type: string
          enum:
            - daily
            - monthly
        currentUsage:
          type: number
          minimum: 0
        limit:
          type: number
          minimum: 0
        percentUsed:
          type: number
          minimum: 0
          maximum: 100

    BudgetExceededData:
      type: object
      required:
        - tenantId
        - userId
        - budgetType
        - limit
        - spend
      properties:
        tenantId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
        budgetType:
          type: string
          enum:
            - daily
            - request
            - monthly
        limit:
          type: number
          format: double
          minimum: 0
        spend:
          type: number
          format: double
          minimum: 0

    ProviderOutageData:
      type: object
      required:
        - provider
        - status
        - errorMessage
        - timestamp
      properties:
        provider:
          type: string
          description: 'Provider identifier (e.g. aws-bedrock, openai).'
        status:
          type: string
          enum:
            - degraded
            - outage
            - recovered
        errorMessage:
          type: string
        timestamp:
          type: string
          format: date-time

    InferenceFailedData:
      type: object
      required:
        - tenantId
        - requestId
        - provider
        - model
        - errorCode
        - errorMessage
        - attemptCount
        - retryable
      properties:
        tenantId:
          type: string
          format: uuid
        requestId:
          type: string
          format: uuid
        provider:
          type: string
        model:
          type: string
        errorCode:
          type: string
        errorMessage:
          type: string
        attemptCount:
          type: integer
          minimum: 1
        retryable:
          type: boolean

    EmbeddingsGeneratedData:
      type: object
      required:
        - tenantId
        - provider
        - model
        - inputCount
        - dimensions
        - tokens
        - costUsd
        - latencyMs
      properties:
        tenantId:
          type: string
          format: uuid
        provider:
          type: string
        model:
          type: string
        inputCount:
          type: integer
          minimum: 1
          description: Number of input texts embedded.
        dimensions:
          type: integer
          minimum: 1
          description: Dimensionality of the output vectors.
        tokens:
          type: integer
          minimum: 0
        costUsd:
          type: number
          format: double
          minimum: 0
        latencyMs:
          type: integer
          minimum: 0

    SemanticCacheHitData:
      type: object
      required:
        - tenantId
        - similarityScore
        - tokensSaved
        - costSaved
        - originalModel
      properties:
        tenantId:
          type: string
          format: uuid
        similarityScore:
          type: number
          format: double
          minimum: 0
          maximum: 1
          description: Cosine similarity between the query and the cached prompt.
        tokensSaved:
          type: integer
          minimum: 0
        costSaved:
          type: number
          format: double
          minimum: 0
        originalModel:
          type: string
          description: Model that would have been invoked without the cache hit.

    KgSyncedData:
      type: object
      required:
        - inferenceRequestId
        - tenantId
        - variantKey
        - success
        - nodeId
      properties:
        inferenceRequestId:
          type: string
          format: uuid
        tenantId:
          type: string
          format: uuid
        variantKey:
          type: string
        success:
          type: boolean
        nodeId:
          type: string
          description: Neptune node identifier created or updated during sync.

  messages:
    LlmUsageEvent:
      name: LlmUsageEvent
      title: LLM Usage Event
      summary: Emitted after a successful LLM inference call with token and cost telemetry.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/LlmUsageData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key.

    QuotaLowEvent:
      name: QuotaLowEvent
      title: Quota Low Event
      summary: Alert when AI credit usage exceeds 80% of the configured quota.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/QuotaLowData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key.

    BudgetExceededEvent:
      name: BudgetExceededEvent
      title: Budget Exceeded Event
      summary: Emitted when a daily, monthly, or per-request budget limit is breached.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/BudgetExceededData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key.

    ProviderOutageEvent:
      name: ProviderOutageEvent
      title: Provider Outage Event
      summary: Emitted when a provider circuit breaker transitions between degraded, outage, or recovered states.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/ProviderOutageData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key (may be system-level).

    InferenceFailedEvent:
      name: InferenceFailedEvent
      title: Inference Failed Event
      summary: Emitted when an inference request fails after exhausting all retry attempts.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/InferenceFailedData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key.

    EmbeddingsGeneratedEvent:
      name: EmbeddingsGeneratedEvent
      title: Embeddings Generated Event
      summary: Emitted after embeddings are successfully generated for one or more inputs.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/EmbeddingsGeneratedData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key.

    SemanticCacheHitEvent:
      name: SemanticCacheHitEvent
      title: Semantic Cache Hit Event
      summary: Emitted when a semantic cache hit avoids a full provider inference call.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/SemanticCacheHitData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key.

    KgSyncedEvent:
      name: KgSyncedEvent
      title: Knowledge Graph Synced Event
      summary: Emitted after an inference result is synced to the Neptune knowledge graph.
      contentType: application/json
      headers:
        $ref: '#/components/schemas/CloudEventEnvelope'
      payload:
        $ref: '#/components/schemas/KgSyncedData'
      bindings:
        kafka:
          key:
            type: string
            format: uuid
            description: tenantId used as Kafka partition key.
