Agent Spaces
Agent Spaces sind benannte, von Admins verfasste Personas, die eine AI-Anfrage beschränken. Wo Agent Skills einzelne Workflows kodifizieren, kodifiziert ein Space eine Sichtweise: System-Prompt, Cube-Allowlist, Skill-Allowlist, vorgeschlagene Prompts — serverseitig durchgesetzt, sodass das LLM, egal was der Aufrufer sendet, die Persona-Stimme + die Cubes der Persona + die Skills der Persona sieht.
Persistiert als JSON unter saiku-home/agent-spaces/. Der Launcher
scannt lazy nach mtime-Signatur (dasselbe Modell wie Skills — kein
Watcher-Thread).
Ausgeliefert in saiku v4.7 als saiku#1440.
Was ein Space durchsetzt
Dateiformat
{ "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" ]}| Feld | Erforderlich | Typ | Anmerkungen |
|---|---|---|---|
id | ja | string | kebab-case, [a-z][a-z0-9-]{0,63}. Pfadsegment in /ai/spaces/{id}/ask. |
name | ja | string | Anzeigename für den Katalog und die Sidebar. |
description | nein | string | Einzeilige Zusammenfassung, im Space-Picker gezeigt. |
systemPrompt | nein | string | Bei jeder Anfrage dem eingebauten SYSTEM_PROMPT vorangestellt. |
cubeAllowlist | ja | AiCubeRef[] | Mindestens ein Eintrag. Refs außerhalb dieser Liste geben 403 FORBIDDEN zurück. |
skillAllowlist | nein | string[] | Filtert Slash-Routing + LLM-Katalog. Leer = alle Skills erlaubt. |
suggestedPrompts | nein | string[] | Freiform-Quickstart-Fragen, die die UI rendern kann. |
Unbekannte Top-Level-Schlüssel werden abgelehnt, sodass ein
Tippfehler (sytemPrompt) als UNKNOWN_FIELD auftaucht, statt still
verworfen zu werden.
Cube-Durchsetzung
-
Der Aufrufer POSTet an
/ai/spaces/{id}/askmit einem optionalencube-Feld:Terminal-Fenster 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?"}' -
Wird
cubeweggelassen, wird der erste allowlistete Eintrag des Space verwendet. -
Wird
cubegeliefert, muss es auf allen vier Koordinaten (connectionName,catalog,schema,cubeName) mit einem Space-Allowlist-Eintrag übereinstimmen, sonst gibt der Aufruf zurück:HTTP 403 Forbidden{"degraded": true,"reason": "FORBIDDEN: cube OtherCube is not in space 'foodmart-sales-analyst' allowlist"}
Das ist beabsichtigt: Eine UI, die dem Server eine veraltete Cube-Ref übergibt, sollte korrigiert werden, nicht still auf den Standard umgedeutet.
System-Prompt-Injection
Der systemPrompt des Space wird providerseitig dem eingebauten
SYSTEM_PROMPT vorangestellt. Die vollständige zusammengesetzte
System-Nachricht, die das LLM sieht:
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 timegrain unless the user asks otherwise. Lead with the top three lines byabsolute value. Flag any figure that swings by more than 20% versus theprior period. Be analytical, brief, and numbers-first.
Cube schema:{ … the AiSchema JSON … }
Cube ref to echo: { … }Die history- und question-Felder des Nutzers reiten unter all dem als
reguläre Nachrichten — nichts, was sie einschleusen können, schreibt die
Persona um.
Skill-Filter
Der Skill-Katalog wird auf die skillAllowlist des Space
gefiltert, bevor er das LLM erreicht:
- Die
skillAllowlistist leer → alle Skills fließen durch. - Die
skillAllowlistbenennt spezifische Skills → nur diese erscheinen im LLM-System-Prompt UND nur diese expandieren per Slash.
Eine Anfrage wie /some-other-skill for Q4 in einem Space, der
some-other-skill nicht allowlistet, fällt als rohe Anfrage durch — das
LLM sieht die Nachricht wörtlich, ohne Expansion. Die
Routing-Entscheidung ist einseitig (Allowlist-Verweigerung), nie
partiell.
Vorgeschlagene Prompts
Jeder Space trägt eine suggestedPrompts-Liste — 3–6 verfasste
Quickstart-Fragen, die die UI als Chips sichtbar macht:
"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"]Slash-Command-Einträge sind zulässig und erwünscht — ein vorgeschlagener
Prompt, der mit / beginnt, ruft den benannten Skill direkt auf.
REST-Oberfläche
GET /rest/saiku/api/ai/spaces
Katalog von {id, name, description, suggestedPrompts}-Zusammenfassungen.
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
Gleiches, plus ein errors[]-Array. Stabile Fehlercodes:
| Code | Wann |
|---|---|
EMPTY_SPACE | Datei ist leer oder nur Leerraum. |
MALFORMED_JSON | JSON-Parser hat den Body abgelehnt. |
MISSING_FIELD | Erforderliches Feld (id, name) nicht vorhanden. |
BLANK_FIELD | Erforderliches Feld vorhanden, aber leer / nur Leerraum. |
TYPE_MISMATCH | Feld vorhanden, aber falscher Typ. |
INVALID_ID | id passt nicht zu [a-z][a-z0-9-]{0,63}. |
EMPTY_ALLOWLIST | cubeAllowlist vorhanden, aber leer — Space wäre unbrauchbar. |
INVALID_CUBE_REF | Allowlist-Eintrag fehlt eine Koordinate (connectionName, etc.). |
UNKNOWN_FIELD | Frontmatter enthält ein Feld, das nicht im Schema ist. |
DUPLICATE_ID | Zwei Dateien deklarierten dieselbe id. |
IO_ERROR | Datei konnte nicht gelesen werden (Dateisystem-Ebene). |
GET /rest/saiku/api/ai/spaces/{id}
Vollständiger Datensatz — enthält systemPrompt und cubeAllowlist,
die die Zusammenfassung auslässt. Verwendet von der Admin-UI beim
Bearbeiten einer Persona.
POST /rest/saiku/api/ai/spaces/{id}/ask
Space-beschränkte Anfrage. Die Body-Form spiegelt
/ai/ask, aber das cube-Feld ist optional:
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"}'Der Antwort-Umschlag ist der Standard-AiAskApi.AskResponse
— model, request (der vom Modell ausgegebene AiQueryRequest) und
degraded/reason bei Fehler.
POST /rest/saiku/api/ai/spaces/{id}/ask/stream
Streaming-Variante der space-beschränkten Anfrage. Gibt dasselbe
Server-Sent-Events-Schema aus wie /ai/ask/stream
(model → intent → chunk → final) mit angewandtem Persona-Scope —
der Client sieht identische Wire-Events, ob er /ai/ask/stream oder
diesen space-beschränkten Spiegel trifft. Space-nicht-gefunden- und
Cube-außerhalb-der-Allowlist-Ergebnisse tauchen als error-Event
gefolgt von einem degraded final auf, sodass der Reader Scope-Fehler
und Provider-Fehler gleich behandelt.
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
Erzwingt einen erneuten Scan (umgeht die mtime-Signaturprüfung).
Spaces im Admin-Panel verfassen
Spaces müssen nicht mehr als handverfasstes JSON vorliegen. Admin → Agent spaces ist ein vollständiger Editor: Schreiben Sie den System-Prompt, haken Sie die Cubes in der Allowlist ab (gestützt auf Live-Cube-Discovery, sodass Sie nur Cubes erlauben können, die existieren), listen Sie die Skills und vorgeschlagenen Prompts auf und speichern. Das Löschen eines Space entfernt seine JSON-Datei.
Der Editor wird von einer admin-geschützten CRUD-Oberfläche gestützt.
Diese Endpunkte erfordern ROLE_ADMIN und geben die vollständige
Persona zurück (System-Prompt + Cube-Allowlist inklusive, anders als der
redigierte öffentliche Katalog oben):
| Methode + Pfad | Zweck |
|---|---|
GET /rest/saiku/admin/agent-spaces | Listet jede Persona vollständig auf, zum Bearbeiten. |
GET /rest/saiku/admin/agent-spaces/errors | Parse-Fehler für fehlerhafte Dateien. |
PUT /rest/saiku/admin/agent-spaces/{id} | Erstellt oder ersetzt eine Persona. Die id wird validiert (kebab-case, gegen Path-Traversal geschützt), bevor die JSON-Datei geschrieben wird. |
DELETE /rest/saiku/admin/agent-spaces/{id} | Entfernt eine Persona und ihre Datei. |
Einen Space einbetten
<saiku-embed kind="ai" space="foodmart-sales-analyst"> setzt einen
persona-beschränkten Assistenten in jede Seite. Die Cube-Allowlist und
der System-Prompt werden serverseitig genau so durchgesetzt wie bei der
REST-Anfrage, sodass ein eingebetteter Assistent nicht von seiner
Persona weggelenkt werden kann. Siehe den Embed-Leitfaden.
Mitgelieferte Beispiele
Frische Saiku-Installationen platzieren zwei funktionierende Personas:
- FoodMart Sales Analyst — analytisch, knapp, zahlenzuerst.
weekly-foodmart-rollupin seiner Skill-Allowlist, sodass/weekly-foodmart-rollupals Slash-Command verfügbar ist. - FoodMart Finance Ops — vorsichtig, präzise, margen-fokussiert. Leere
skillAllowlist= alle Skills erlaubt.
Beide beschränken sich auf den FoodMart-Sales-Cube — eine frische Demo hat Personas zum Anklicken bereit, ohne jegliches Operator-Verfassen.
Nicht-Ziele für v1
- Beschränkung pro Nutzer oder pro Rolle. Spaces sind in v1 pro Launcher; Multi-Tenant-Workspaces können Beschränkung schichten, indem sie Workspace-Verzeichnisse auf Registry-Roots pro Workspace mappen — zurückgestellt.
- Daten-Scope-Override pro Space. Eingebettete Abfragen setzen bereits erzwungene Row-Level-Filter durch (apply-or-fail-closed — siehe den Embed-Leitfaden), aber das Anpinnen von RLS-Filtern speziell auf space-beschränkte Anfragen wird noch mit der Ossie-RLS-Arbeit in saiku#1393 verfolgt.