Saltearse al contenido

Agent Spaces

Agent Spaces son personas nombradas y escritas por admins que limitan una ask de IA. Donde las Agent Skills codifican flujos de trabajo individuales, un espacio codifica un punto de vista: system prompt, lista de cubos permitidos, lista de skills permitidas, prompts sugeridos — aplicado en el servidor para que, sin importar lo que envíe el llamador, el LLM vea la voz de la persona + los cubos de la persona + las skills de la persona.

Persistido como JSON bajo saiku-home/agent-spaces/. El launcher escanea de forma perezosa por firma de mtime (mismo modelo que las skills — sin hilo vigilante).

Entregado en saiku v4.7 como saiku#1440.

Qué aplica un espacio

Formato de archivo

saiku-home/agent-spaces/foodmart-sales-analyst.json
{
"id": "foodmart-sales-analyst",
"name": "FoodMart Sales Analyst",
"description": "Weekly and monthly sales rollups over the FoodMart Sales cube.",
"systemPrompt": "You are the FoodMart Sales Analyst. Prefer weekly and monthly time grain unless the user asks otherwise. Lead with the top three lines by absolute value. Flag any figure that swings by more than 20% versus the prior period. Be analytical, brief, and numbers-first.",
"cubeAllowlist": [
{"connectionName": "unknown_foodmart", "catalog": "FoodMart", "schema": "FoodMart", "cubeName": "Sales"}
],
"skillAllowlist": ["weekly-foodmart-rollup"],
"suggestedPrompts": [
"How did Store Sales track last week vs the prior week?",
"Break down Store Sales by Product Family for Q4.",
"/weekly-foodmart-rollup"
]
}
CampoRequeridoTipoNotas
idstringkebab-case, [a-z][a-z0-9-]{0,63}. Segmento de ruta en /ai/spaces/{id}/ask.
namestringNombre para mostrar en el catálogo y la barra lateral.
descriptionnostringResumen de una línea mostrado en el selector de espacios.
systemPromptnostringAntepuesto al SYSTEM_PROMPT incorporado en cada ask.
cubeAllowlistAiCubeRef[]Al menos una entrada. Las refs fuera de esta lista devuelven 403 FORBIDDEN.
skillAllowlistnostring[]Filtra el slash-routing + catálogo del LLM. Vacío = todas las skills permitidas.
suggestedPromptsnostring[]Preguntas de inicio rápido de forma libre que la UI puede renderizar.

Las claves de nivel superior desconocidas son rechazadas para que un error tipográfico (sytemPrompt) aflore como UNKNOWN_FIELD en lugar de descartarse silenciosamente.

Aplicación de cubos

  1. El llamador hace POST a /ai/spaces/{id}/ask con un campo opcional cube:

    Ventana de terminal
    curl -sS -X POST -H 'Content-Type: application/json' \
    -u admin:admin \
    http://localhost:8080/saiku/api/ai/spaces/foodmart-sales-analyst/ask \
    -d '{"question": "How did Store Sales track last week?"}'
  2. Si cube se omite, se usa la primera entrada permitida del espacio.

  3. Si cube se suministra, debe coincidir con una entrada de la lista permitida del espacio en las cuatro coordenadas (connectionName, catalog, schema, cubeName) o la llamada devuelve:

    HTTP 403 Forbidden
    {
    "degraded": true,
    "reason": "FORBIDDEN: cube OtherCube is not in space 'foodmart-sales-analyst' allowlist"
    }

Esto es deliberado: una UI que le entrega al servidor una ref de cubo obsoleta debería ser corregida, no reinterpretada silenciosamente hacia la por defecto.

Inyección de system prompt

El systemPrompt del espacio se antepone al SYSTEM_PROMPT incorporado en el lado del proveedor. El mensaje de sistema completo ensamblado que el LLM ve:

You are a Mondrian OLAP analyst assistant scoped to a single cube. …
[…the built-in tool-choice rails…]
Agent space persona:
You are the FoodMart Sales Analyst. Prefer weekly and monthly time
grain unless the user asks otherwise. Lead with the top three lines by
absolute value. Flag any figure that swings by more than 20% versus the
prior period. Be analytical, brief, and numbers-first.
Cube schema:
{ … the AiSchema JSON … }
Cube ref to echo: { … }

Los campos history y question del usuario cabalgan por debajo de todo eso como mensajes regulares — nada que puedan inyectar reescribe la persona.

Filtro de skills

El catálogo de skills se filtra a la skillAllowlist del espacio antes de que llegue al LLM:

  • La skillAllowlist está vacía → todas las skills fluyen.
  • La skillAllowlist nombra skills específicas → solo esas aparecen en el system prompt del LLM Y solo esas se expanden con slash.

Una ask como /some-other-skill for Q4 en un espacio que no permite some-other-skill cae como una ask cruda — el LLM ve el mensaje literalmente, sin expansión. La decisión de enrutamiento es unilateral (denegación por lista permitida), nunca parcial.

Prompts sugeridos

Cada espacio lleva una lista suggestedPrompts — 3-6 preguntas de inicio rápido escritas que la UI expone como chips:

"suggestedPrompts": [
"How did Store Sales track last week vs the prior week?",
"Break down Store Sales by Product Family for Q4.",
"Which Product Department is up the most month-over-month?",
"/weekly-foodmart-rollup"
]

Las entradas de slash-command son legales y fomentadas — un prompt sugerido que empieza con / invoca la skill nombrada directamente.

Superficie REST

GET /rest/saiku/api/ai/spaces

Catálogo de resúmenes {id, name, description, suggestedPrompts}.

Ventana de terminal
curl -sS -u admin:admin \
http://localhost:8080/saiku/api/ai/spaces | jq
{
"spaces": [
{
"id": "foodmart-sales-analyst",
"name": "FoodMart Sales Analyst",
"description": "Weekly and monthly sales rollups over the FoodMart Sales cube.",
"suggestedPrompts": ["How did Store Sales track last week?", ""]
}
]
}

GET /rest/saiku/api/ai/spaces?errors=true

Lo mismo, más un array errors[]. Códigos de error estables:

CódigoCuándo
EMPTY_SPACEEl archivo está vacío o es todo espacios en blanco.
MALFORMED_JSONEl parser JSON rechazó el cuerpo.
MISSING_FIELDCampo requerido (id, name) no presente.
BLANK_FIELDCampo requerido presente pero vacío / solo espacios en blanco.
TYPE_MISMATCHCampo presente pero de tipo incorrecto.
INVALID_IDid no coincide con [a-z][a-z0-9-]{0,63}.
EMPTY_ALLOWLISTcubeAllowlist presente pero vacía — el espacio sería inutilizable.
INVALID_CUBE_REFA una entrada de la lista permitida le falta una coordenada (connectionName, etc.).
UNKNOWN_FIELDEl frontmatter contiene un campo que no está en el schema.
DUPLICATE_IDDos archivos declararon el mismo id.
IO_ERRORNo se pudo leer el archivo (a nivel de sistema de archivos).

GET /rest/saiku/api/ai/spaces/{id}

Registro completo — incluye systemPrompt y cubeAllowlist que el resumen omite. Usado por la UI de admin al editar una persona.

POST /rest/saiku/api/ai/spaces/{id}/ask

Ask limitada al espacio. La forma del cuerpo refleja /ai/ask pero el campo cube es opcional:

Ventana de terminal
curl -sS -X POST -H 'Content-Type: application/json' \
-u admin:admin \
http://localhost:8080/saiku/api/ai/spaces/foodmart-sales-analyst/ask \
-d '{"question": "Break down Store Sales by Product Family for Q4"}'

El sobre de respuesta es el estándar AiAskApi.AskResponsemodel, request (el AiQueryRequest que el modelo emitió), y degraded/reason en caso de error.

POST /rest/saiku/api/ai/spaces/{id}/ask/stream

Variante de streaming de la ask limitada al espacio. Emite el mismo schema de Server-Sent Events que /ai/ask/stream (modelintentchunkfinal) con el alcance de persona aplicado — el cliente ve eventos de cable idénticos tanto si golpea /ai/ask/stream como este espejo limitado al espacio. Los desenlaces de espacio-no-encontrado y de cubo fuera de la lista permitida afloran como un evento error seguido de un final degradado, así que el lector maneja los fallos de alcance y los fallos de proveedor de la misma forma.

Ventana de terminal
curl -sS -N -X POST -H 'Content-Type: application/json' \
-u admin:admin \
http://localhost:8080/saiku/api/ai/spaces/foodmart-sales-analyst/ask/stream \
-d '{"question": "Break down Store Sales by Product Family for Q4"}'

POST /rest/saiku/api/ai/spaces/refresh

Fuerza un reescaneo (se salta la comprobación de firma de mtime).

Escribir espacios en el panel de admin

Los espacios ya no tienen que ser JSON escrito a mano. Admin → Agent spaces es un editor completo: escriba el system prompt, marque los cubos en la lista permitida (respaldado por descubrimiento de cubos en vivo, así que solo puede permitir cubos que existen), liste las skills y los prompts sugeridos, y guarde. Eliminar un espacio quita su archivo JSON.

El editor está respaldado por una superficie CRUD limitada a admin. Estos endpoints requieren ROLE_ADMIN y devuelven la persona completa (system prompt + lista de cubos permitidos incluidos, a diferencia del catálogo público redactado de arriba):

Método + rutaPropósito
GET /rest/saiku/admin/agent-spacesLista cada persona en su totalidad, para editar.
GET /rest/saiku/admin/agent-spaces/errorsErrores de parseo para archivos malformados.
PUT /rest/saiku/admin/agent-spaces/{id}Crea o reemplaza una persona. El id se valida (kebab-case, protegido contra path-traversal) antes de escribir el archivo JSON.
DELETE /rest/saiku/admin/agent-spaces/{id}Elimina una persona y su archivo.

Incrustar un espacio

<saiku-embed kind="ai" space="foodmart-sales-analyst"> coloca un asistente limitado a la persona en cualquier página. La lista de cubos permitidos y el system prompt se aplican en el servidor exactamente como para la ask REST, así que un asistente incrustado no puede ser desviado de su persona. Vea la guía de embed.

Ejemplos incluidos

Las instalaciones nuevas de Saiku preparan dos personas funcionales:

  • FoodMart Sales Analyst — analítica, breve, orientada a números primero. weekly-foodmart-rollup en su lista de skills permitidas así que /weekly-foodmart-rollup está disponible como slash command.
  • FoodMart Finance Ops — cautelosa, precisa, orientada al margen. skillAllowlist vacía = todas las skills permitidas.

Ambas limitan al cubo FoodMart Sales — una demo nueva tiene personas listas para pulsar sin ninguna escritura por parte del operador.

No-objetivos para v1

  • Alcance por usuario o por rol. Los espacios son por launcher en v1; los workspaces multi-tenant pueden superponer el alcance mapeando directorios de workspace sobre raíces de registro por workspace — diferido.
  • Sobrescritura de alcance de datos por espacio. Las consultas incrustadas ya aplican filtros forzados a nivel de fila (aplicar-o-fallar-cerrado — vea la guía de embed), pero fijar filtros RLS sobre asks limitadas a espacio específicamente sigue siendo rastreado con el trabajo de RLS de Ossie en saiku#1393.

A dónde ir después