Skip to content

Core · Service · Active

platform-ai-service

Provider-agnostic AI boundary for the workspace, exposing a stable internal contract for text generation with pluggable providers.

  • TypeScript
  • NestJS 11
  • PostgreSQL
  • OpenAI SDK
  • Responses API
  • @platform/contracts-ai
  • @platform/observability

Spec sheet

Boundary

Core / AI

Runtime

NestJS 11 HTTP service

Default port

3300

Persistence

PostgreSQL via AI_DATABASE_URL

Security

Required PLATFORM_INTERNAL_TOKEN plus forwarded bearer validation via platform-auth-service

Providers

Postgres-managed registry with openai and template support

Responsibilities

  • Expose a stable HTTP contract for synchronous text generations.
  • Keep provider selection behind a provider registry.
  • Support OpenAI via Responses API and a local template fallback.
  • Persist provider configuration and default routing through admin endpoints.
  • Allow consumers to inspect configured and enabled providers.

Interfaces and contract surface

  • GET /health
  • GET /internal/ai/providers
  • GET /internal/ai/providers/admin
  • GET /internal/ai/providers/:providerKey
  • PUT /internal/ai/providers/:providerKey
  • POST /internal/ai/generations

Consumers

Dependencies and external touchpoints

Notes

  • Funnel IA still contains legacy AI integrations that should progressively move behind this service.
  • Always inspect /internal/ai/providers first if you need to know whether openai is really configured in the current environment.
  • Provider enablement and default model routing are runtime state in Postgres, not environment-only configuration.
  • The template provider is deterministic and intended for local tests and fallback scenarios.

Source references

  • platform-ai-service/README.md
  • docs/core-services-integration.md
  • platform-ai-service/package.json

Come integrarsi davvero

Questa surface e pensata per backend/BFF e worker. Il frontend non deve chiamare platform-ai-service direttamente.

Variabili utili

bash
export AI_URL=http://127.0.0.1:3300
export INTERNAL_TOKEN=platform-local-stack-internal-token

1. Scopri provider disponibili e default effettivo

Prima di integrare la generazione, conviene leggere /internal/ai/providers: ti dice quali provider sono abilitati, quali sono configurati davvero e quale verra usato come default.

bash
curl -sS "$AI_URL/internal/ai/providers" \
  -H "x-platform-internal-token: $INTERNAL_TOKEN"

Se openai risulta configured: false, la route di generazione deve usare un provider disponibile, in genere template per smoke test locali. La configurazione provider viene letta dallo state store PostgreSQL, non da sole variabili ambiente.

2. Ispeziona configurazione admin

Le viste operations e gli strumenti interni usano anche la surface admin per dettaglio e aggiornamento provider:

bash
curl -sS "$AI_URL/internal/ai/providers/admin" \
  -H "x-platform-internal-token: $INTERNAL_TOKEN"
bash
curl -sS "$AI_URL/internal/ai/providers/template" \
  -H "x-platform-internal-token: $INTERNAL_TOKEN"

3. Generazione locale deterministica con provider template

Questo e il percorso piu rapido per verificare contratto HTTP, timeout, retry applicativi e mapping della risposta senza dipendere da credenziali esterne.

bash
curl -sS -X POST "$AI_URL/internal/ai/generations" \
  -H "Content-Type: application/json" \
  -H "x-platform-internal-token: $INTERNAL_TOKEN" \
  -d '{
    "providerKey": "template",
    "instructions": "Rispondi in una sola frase tecnica.",
    "input": "Descrivi il ruolo di platform-ai-service."
  }'

4. Generazione con OpenAI

Il backend prodotto deve applicare le policy utente prima di chiamare il servizio core. Authorization: Bearer <session-token-auth> non sostituisce mai x-platform-internal-token.

bash
curl -sS -X POST "$AI_URL/internal/ai/generations" \
  -H "Content-Type: application/json" \
  -H "x-platform-internal-token: $INTERNAL_TOKEN" \
  -d '{
    "providerKey": "openai",
    "model": "gpt-5-mini",
    "instructions": "Rispondi in italiano con tono tecnico.",
    "input": "Scrivi due frasi su come un backend di prodotto deve usare questo servizio.",
    "metadata": {
      "tenantId": "demo-tenant",
      "feature": "product-description"
    }
  }'

La risposta espone sempre un contratto stabile:

  • generationId per correlazione applicativa
  • providerKey e model effettivamente usati
  • outputText gia normalizzato
  • usage con token input/output/total
  • providerRequestId e providerResponseId per tracing provider-specifico

Un consumer reale lato backend e funnel-ia-engine/backend/src/platform/platform-ai.client.ts.

Endpoint reference

Header comuni per tutte le route interne:

  • x-platform-internal-token: $INTERNAL_TOKEN
  • Authorization: Bearer <ACCESS_TOKEN> opzionale, solo per propagare il contesto utente gia validato dal BFF
EndpointScopoRequestEsempioRisposta rappresentativaErrori e consumer
GET /healthVerifica liveness del servizio.Nessun body.curl -sS "$AI_URL/health"{"status":"ok","service":"platform-ai-service"}Errori infrastrutturali 5xx. Consumer: status dashboard e smoke locali.
GET /internal/ai/providersLegge provider disponibili e default effettivo per i consumer.Header interno.curl -sS "$AI_URL/internal/ai/providers" -H "x-platform-internal-token: $INTERNAL_TOKEN"{"defaultProviderKey":"template","items":[{"key":"template","label":"Template","configured":true,"defaultModel":"template-local","capabilities":{"textGeneration":true,"metadata":true,"customBaseUrl":false}}]}401/403 token mancante o non valido. Consumer: BFF, MCP, agent service.
GET /internal/ai/providers/adminElenca configurazioni provider per viste operations.Header interno.curl -sS "$AI_URL/internal/ai/providers/admin" -H "x-platform-internal-token: $INTERNAL_TOKEN"{"items":[{"key":"openai","enabled":true,"configured":false,"defaultModel":"gpt-5-mini","redactedConfig":{}}]}401/403 auth tecnica, 5xx state store. Consumer: status/operations e admin BFF.
GET /internal/ai/providers/:providerKeyDettaglio admin di un provider con secret redatti.Path providerKey.curl -sS "$AI_URL/internal/ai/providers/openai" -H "x-platform-internal-token: $INTERNAL_TOKEN"{"key":"openai","enabled":true,"configured":true,"defaultModel":"gpt-5-mini","redactedConfig":{"apiKey":"***"}}404 provider sconosciuto. Consumer: operations e MCP diagnostics.
PUT /internal/ai/providers/:providerKeyAggiorna enablement, default model e config provider.JSON admin provider.curl -sS -X PUT "$AI_URL/internal/ai/providers/openai" -H "Content-Type: application/json" -H "x-platform-internal-token: $INTERNAL_TOKEN" -d '{"enabled":true,"defaultModel":"gpt-5-mini","config":{"apiKey":"<OPENAI_API_KEY>"}}'{"key":"openai","enabled":true,"configured":true,"defaultModel":"gpt-5-mini"}400 body non valido, 401/403 token, 404 provider. Consumer: console operations, non frontend.
POST /internal/ai/generationsCrea una generazione testo sincrona usando provider e modello scelti o default.providerKey?, model?, instructions?, input, metadata?.curl -sS -X POST "$AI_URL/internal/ai/generations" -H "Content-Type: application/json" -H "x-platform-internal-token: $INTERNAL_TOKEN" -d '{"providerKey":"template","instructions":"Rispondi breve.","input":"ping","metadata":{"tenantId":"demo"}}'{"generationId":"gen_123","providerKey":"template","model":"template-local","outputText":"pong","usage":{"inputTokens":1,"outputTokens":1,"totalTokens":2},"providerRequestId":null,"providerResponseId":null}400 input mancante, 503 provider non configurato, errori provider normalizzati. Consumer: MCP, agent service, BFF prodotto.

Contratto request/response

POST /internal/ai/generations usa @platform/contracts-ai:

json
{
  "providerKey": "template",
  "model": "template-local",
  "instructions": "Rispondi in italiano.",
  "input": "Testo utente o prompt normalizzato dal BFF.",
  "metadata": {
    "tenantId": "demo",
    "feature": "chat"
  }
}

La risposta stabile espone generationId, providerKey, model, outputText, usage.inputTokens, usage.outputTokens, usage.totalTokens e gli id provider opzionali.

Workspace reference: /Users/jeanpaul/projects/cs-repository