# AI Search Infra Ports

This module guide covers the provider-neutral semantic infrastructure boundary introduced for AI Search PR6.

For the cross-cutting AI Search architecture, rollout gates, and risk controls,
start with [AI Search Architecture](./AI_SEARCH_ARCHITECTURE.md).

## Files

- `src/lib/search/ai/providers/EmbeddingProvider.ts`.
- `src/lib/search/ai/providers/SemanticIndexPort.ts`.
- `src/lib/search/ai/providers/types.ts`.
- `src/lib/search/ai/providers/fail-soft.ts`.
- `src/lib/search/ai/providers/factory.ts`.
- `src/lib/search/ai/providers/openai-embedding-provider.ts`.
- `src/lib/search/ai/providers/weaviate-semantic-index.ts`.
- `src/lib/search/ai/retrieval/openai-grounded-answer.ts`.
- `src/lib/search/ai/retrieval/grounded-answer-service.ts`.

## Goals

- Keep the embedding provider replaceable.
- Keep the vector backend replaceable.
- Keep grounded answer generation replaceable and explicitly gated.
- Make semantic infrastructure fail soft so later search routes can fall back to standard search instead of failing hard.
- Keep all runtime behavior disabled unless explicit AI infra configuration exists.

## Contracts

`EmbeddingProvider`

- Accepts provider-neutral `EmbeddingRequest` values.
- Returns `EmbeddingResult` with `status: "success" | "disabled" | "unavailable"`.
- Does not throw infrastructure failures across the public boundary when wrapped by the fail-soft adapter.

`SemanticIndexPort`

- Supports provider-neutral vector `upsert`, `query`, and `delete`.
- Uses canonical chunk metadata including `userId`, `service`, `accountId`, `resourceId`, `chunkId`, `mimeType`, `modifiedAt`, and `indexedAt`.
- Returns empty hits or zero-count outcomes when the backend is disabled or unavailable.

## Runtime Config

The AI runtime config now parses both rollout flags and infra provider settings:

- `AI_EMBEDDING_PROVIDER`.
- `AI_EMBEDDING_BASE_URL`.
- `AI_EMBEDDING_API_KEY`.
- `AI_EMBEDDING_MODEL`.
- `AI_EMBEDDING_TIMEOUT_MS`.
- `AI_VECTOR_BACKEND`.
- `AI_VECTOR_BASE_URL`.
- `AI_VECTOR_API_KEY`.
- `AI_SEMANTIC_INDEX_NAME`.
- `AI_SEMANTIC_INDEX_SCHEMA_VERSION`.
- `AI_VECTOR_TIMEOUT_MS`.
- `AI_VECTOR_QUERY_TIMEOUT_MS`.
- `AI_VECTOR_UPSERT_TIMEOUT_MS`.
- `AI_VECTOR_DELETE_TIMEOUT_MS`.
- `AI_RAG_PROVIDER`.
- `AI_RAG_BASE_URL`.
- `AI_RAG_API_KEY`.
- `AI_RAG_MODEL`.
- `AI_RAG_TIMEOUT_MS`.
- `AI_INFRA_CIRCUIT_BREAKER_ENABLED`.
- `AI_INFRA_CIRCUIT_BREAKER_FAILURE_THRESHOLD`.
- `AI_INFRA_CIRCUIT_BREAKER_RESET_TIMEOUT_MS`.

Defaults stay safe:

- rollout flags default to `false`.
- provider selections default to `disabled`.
- factories return disabled adapters unless the selected backend is both configured and resolvable through the built-in or injected registry.
- Ask AI remains unavailable unless `AI_RAG_ENABLED=true`, the semantic stack is configured, and grounded answer generation has its own usable model config.

## Fail-Soft Behavior

The fail-soft wrapper applies three protections at the adapter boundary:

- operation timeouts.
- lightweight circuit breaker.
- unavailable results instead of thrown adapter errors.

Later search code should treat `status !== "success"` as a signal to fall back to keyword or full-text behavior.

Grounded answers follow the same fail-soft rule:

- if embeddings or semantic retrieval are unavailable, Ask AI returns a safe `no_answer`.
- if answer generation is unavailable, Ask AI returns a safe `no_answer`.
- `AI_RAG_TIMEOUT_MS` aborts slow grounded-answer generation requests instead of waiting indefinitely.
- callers must never convert those states into fabricated answers.

## PR7 Concrete Adapters

PR7 adds the first concrete AI infra implementations behind the neutral contracts:

- `openai` for embeddings.
- `weaviate` for the semantic index.

Factory registration still flows through `createAiInfraPorts(...)`:

1. `readAiSearchRuntimeConfig()` resolves the neutral runtime config.
2. `createAiInfraAdapterRegistry(config)` builds the built-in adapter registry from that config.
3. `createAiInfraPorts({ registry })` merges any caller-supplied registry entries on top of the built-ins.
4. The selected adapter is wrapped by the existing fail-soft timeout and circuit-breaker boundary.

No route or indexing code should instantiate OpenAI or Weaviate adapters directly.

## PR8 Guidance

When provider-specific adapters arrive:

1. Implement the provider or backend behind these ports, not in routes.
2. Resolve semantic ports through `createAiInfraPorts(...)`, not by importing concrete adapters.
3. Let the fail-soft wrapper own timeout and circuit-breaker behavior.
4. Keep provider-specific request/response details inside the adapter; shared callers should only see the neutral contracts from `providers/types.ts`.
5. Pass only canonical scope metadata (`userId`, `service`, `accountId`, `resourceId`, `chunkId`) to the semantic index; do not construct backend-native filters outside the adapter.
