Agent Spaces
Agent Spaces to nazwane persony autorstwa administratora, które ograniczają ask AI. Tam gdzie Agent Skills kodyfikują pojedyncze przepływy, przestrzeń kodyfikuje punkt widzenia: system prompt, listę dozwolonych kostek, listę dozwolonych skilli, sugerowane prompty — wymuszane po stronie serwera, więc bez względu na to, co wysyła wywołujący, LLM widzi głos persony + kostki persony + skille persony.
Utrwalane jako JSON pod saiku-home/agent-spaces/. Launcher skanuje
leniwie po sygnaturze mtime (ten sam model co skille — brak wątku
obserwatora).
Dostarczone w saiku v4.7 jako saiku#1440.
Co wymusza przestrzeń
Format pliku
{ "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" ]}| Pole | Wymagane | Typ | Uwagi |
|---|---|---|---|
id | tak | string | kebab-case, [a-z][a-z0-9-]{0,63}. Segment ścieżki w /ai/spaces/{id}/ask. |
name | tak | string | Nazwa wyświetlana dla katalogu i paska bocznego. |
description | nie | string | Jednolinijkowe podsumowanie pokazywane w wyborze przestrzeni. |
systemPrompt | nie | string | Doklejany przed wbudowanym SYSTEM_PROMPT przy każdym ask. |
cubeAllowlist | tak | AiCubeRef[] | Co najmniej jeden wpis. Referencje spoza tej listy zwracają 403 FORBIDDEN. |
skillAllowlist | nie | string[] | Filtruje kierowanie slash + katalog LLM. Pusta = wszystkie skille dozwolone. |
suggestedPrompts | nie | string[] | Dowolne pytania szybkiego startu, które UI może wyrenderować. |
Nieznane klucze najwyższego poziomu są odrzucane, więc literówka
(sytemPrompt) ujawnia się jako UNKNOWN_FIELD, a nie jest cicho
odrzucana.
Wymuszanie kostki
-
Wywołujący wysyła POST do
/ai/spaces/{id}/askz opcjonalnym polemcube:Okno terminala 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?"}' -
Jeśli
cubejest pominięte, używany jest pierwszy dozwolony wpis przestrzeni. -
Jeśli
cubejest podane, musi pasować do wpisu listy dozwolonych przestrzeni na wszystkich czterech współrzędnych (connectionName,catalog,schema,cubeName), inaczej wywołanie zwraca:HTTP 403 Forbidden{"degraded": true,"reason": "FORBIDDEN: cube OtherCube is not in space 'foodmart-sales-analyst' allowlist"}
To jest zamierzone: UI, które podaje serwerowi nieaktualną referencję kostki, powinno zostać skorygowane, a nie cicho zreinterpretowane na domyślną.
Wstrzyknięcie system promptu
systemPrompt przestrzeni jest doklejany przed wbudowanym
SYSTEM_PROMPT po stronie dostawcy. Pełna złożona wiadomość systemowa,
którą widzi LLM:
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: { … }Pola history i question użytkownika jadą poniżej tego wszystkiego
jako zwykłe wiadomości — nic, co mogą wstrzyknąć, nie przepisuje persony.
Filtr skilli
Katalog skilli jest filtrowany do skillAllowlist
przestrzeni, zanim dotrze do LLM:
skillAllowlistjest pusta → wszystkie skille przepływają.skillAllowlistnazywa konkretne skille → tylko te pojawiają się w system prompcie LLM ORAZ tylko te rozwijają się przez slash.
Ask w rodzaju /some-other-skill for Q4 w przestrzeni, która nie ma
some-other-skill na liście dozwolonych, spada jako surowy ask — LLM
widzi wiadomość dosłownie, bez rozwinięcia. Decyzja o kierowaniu jest
jednostronna (deny listy dozwolonych), nigdy częściowa.
Sugerowane prompty
Każda przestrzeń niesie listę suggestedPrompts — 3-6 autorskich pytań
szybkiego startu, które UI ujawnia jako chipy:
"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"]Wpisy poleceń slash są legalne i zachęcane — sugerowany prompt
zaczynający się od / wywołuje nazwany skill bezpośrednio.
Powierzchnia REST
GET /rest/saiku/api/ai/spaces
Katalog podsumowań {id, name, description, suggestedPrompts}.
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
To samo, plus tablica errors[]. Stabilne kody błędów:
| Kod | Kiedy |
|---|---|
EMPTY_SPACE | Plik jest pusty lub całkowicie białe znaki. |
MALFORMED_JSON | Parser JSON odrzucił ciało. |
MISSING_FIELD | Wymagane pole (id, name) nieobecne. |
BLANK_FIELD | Wymagane pole obecne, ale puste / same białe znaki. |
TYPE_MISMATCH | Pole obecne, ale zły typ. |
INVALID_ID | id nie pasuje do [a-z][a-z0-9-]{0,63}. |
EMPTY_ALLOWLIST | cubeAllowlist obecne, ale puste — przestrzeń byłaby bezużyteczna. |
INVALID_CUBE_REF | Wpis listy dozwolonych bez współrzędnej (connectionName itp.). |
UNKNOWN_FIELD | Frontmatter zawiera pole spoza schemy. |
DUPLICATE_ID | Dwa pliki zadeklarowały to samo id. |
IO_ERROR | Nie udało się odczytać pliku (poziom systemu plików). |
GET /rest/saiku/api/ai/spaces/{id}
Pełny rekord — zawiera systemPrompt i cubeAllowlist, które
podsumowanie pomija. Używany przez UI admina przy edycji persony.
POST /rest/saiku/api/ai/spaces/{id}/ask
Ask ograniczony do przestrzeni. Kształt ciała odzwierciedla
/ai/ask, ale pole cube jest opcjonalne:
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"}'Koperta odpowiedzi to standardowa AiAskApi.AskResponse
— model, request (AiQueryRequest, który model wyemitował) oraz
degraded/reason przy błędzie.
POST /rest/saiku/api/ai/spaces/{id}/ask/stream
Wariant strumieniowy ask-a ograniczonego do przestrzeni. Emituje tę samą
schemę Server-Sent Events co /ai/ask/stream
(model → intent → chunk → final) z zastosowanym zakresem persony
— klient widzi identyczne zdarzenia na drucie, czy uderza /ai/ask/stream,
czy to lustro ograniczone do przestrzeni. Wyniki przestrzeni-nie-znaleziono
i kostki-spoza-listy-dozwolonych ujawniają się jako zdarzenie error, po
którym następuje zdegradowany final, więc czytnik obsługuje błędy
zakresu i błędy dostawcy tak samo.
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
Wymuś ponowny skan (omija sprawdzenie sygnatury mtime).
Autorowanie przestrzeni w panelu admina
Przestrzenie nie muszą już być ręcznie pisanym JSON-em. Admin → Agent spaces to pełny edytor: napisz system prompt, odhacz kostki na liście dozwolonych (wspartej odkrywaniem kostek na żywo, więc możesz dopuścić tylko istniejące kostki), wylistuj skille i sugerowane prompty, i zapisz. Usunięcie przestrzeni usuwa jej plik JSON.
Edytor jest wsparty przez powierzchnię CRUD bramkowaną adminem. Te
endpointy wymagają ROLE_ADMIN i zwracają pełną personę (system
prompt + lista dozwolonych kostek włączone, w przeciwieństwie do
zredagowanego publicznego katalogu powyżej):
| Metoda + ścieżka | Cel |
|---|---|
GET /rest/saiku/admin/agent-spaces | Wylistuj każdą personę w całości, do edycji. |
GET /rest/saiku/admin/agent-spaces/errors | Błędy parsowania dla wadliwych plików. |
PUT /rest/saiku/admin/agent-spaces/{id} | Utwórz lub zamień personę. id jest walidowane (kebab-case, zabezpieczone przed path-traversal) przed zapisaniem pliku JSON. |
DELETE /rest/saiku/admin/agent-spaces/{id} | Usuń personę i jej plik. |
Osadzanie przestrzeni
<saiku-embed kind="ai" space="foodmart-sales-analyst"> wrzuca
asystenta ograniczonego do persony na dowolną stronę. Lista dozwolonych
kostek i system prompt są wymuszane po stronie serwera dokładnie tak jak
dla ask-a REST, więc osadzony asystent nie może być zsterowany poza
swoją personę. Zobacz przewodnik po embedowaniu.
Dołączone przykłady
Świeże instalacje Saiku umieszczają dwie działające persony:
- FoodMart Sales Analyst — analityczny, zwięzły, liczby-najpierw.
weekly-foodmart-rollupna jego liście dozwolonych skilli, więc/weekly-foodmart-rollupjest dostępny jako polecenie slash. - FoodMart Finance Ops — ostrożny, precyzyjny, skupiony na marży. Pusta
skillAllowlist= wszystkie skille dozwolone.
Obie ograniczają się do kostki FoodMart Sales — świeże demo ma persony gotowe do kliknięcia bez żadnego autorowania przez operatora.
Nie-cele dla v1
- Zakres per-użytkownik lub per-rola. Przestrzenie są per-launcher w v1; wielodostępne workspace’y mogą nakładać zakres, mapując katalogi workspace na korzenie rejestru per-workspace — odroczone.
- Nadpisanie zakresu danych per-przestrzeń. Osadzone zapytania już wymuszają wymuszone filtry na poziomie wierszy (stosuj-albo-zawiedź-zamknięcie — zobacz przewodnik po embedowaniu), ale przypinanie filtrów RLS konkretnie do ask-ów ograniczonych do przestrzeni jest wciąż śledzone razem z pracą nad Ossie RLS w saiku#1393.