diff --git a/modules/ROOT/pages/api-changelog.adoc b/modules/ROOT/pages/api-changelog.adoc index dbee4d36f..95e141cfb 100644 --- a/modules/ROOT/pages/api-changelog.adoc +++ b/modules/ROOT/pages/api-changelog.adoc @@ -8,6 +8,105 @@ This page documents the changes introduced in each release of the Visual Embed SDK. For information about the REST API v2.0 changes, see the xref:rest-apiv2-changelog.adoc[REST API v2.0 changelog]. +== Version 1.53.0, October 2026 + +[width="100%", cols="1,4"] +|==== +|[tag greenBackground]#NEW# +a| +[discrete] +===== Spotter Analyst embed +You can now embed a single, pinned Spotter Analyst in `SpotterEmbed` by using `spotterAnalystConfig.analystId`. +For more information, see xref:embed-spotter-analyst.adoc[Embed Spotter Analyst]. + +|[tag greenBackground]#NEW# +a| +[discrete] +===== Spotter embedding + +`spotterChatPinConfig`:: +You can now let users pin conversations in the chat history sidebar. Use the `spotterChatPinConfig` object in `spotterSidebarConfig` to turn pinning on (`enabled`) and to customize the labels of the *Pin* and *Unpin* options (`pinLabel` and `unpinLabel`). For more information, see xref:customize-spotter-sidebar.adoc#pinning-conversations[Pinning conversations]. + +`starterPrompts`:: +You can now customize the starter prompt pills in the embedded Spotter interface by using the `starterPrompts` object in `spotterChatConfig`. The object supports the `enable`, `quick`, `research`, `previewData`, and `liveboard` keys. To show or hide individual pills, use `Action.QuickSearchPill`, `Action.DeepAnalysisPill`, and `Action.DataLiteracyPill`. For more information, see xref:embed-spotter-analyst.adoc#_customizing_starter_prompt_pills[Customizing starter prompt pills]. + +|[tag greenBackground]#NEW# +a| +[discrete] +===== Liveboards in embedded view +The SDK includes the following enhancements for the Liveboards in your embedded app. + +* `isScopedLiveboardFilteringEnabled` + +Enables scoping filters and parameters to a group of visualizations on a Liveboard, in addition to the Liveboard and tab levels. Supported in `AppEmbed` and `LiveboardEmbed`. +* `openSpotterOnLiveboardByDefault` + +Opens the Spotter chat panel automatically when a Liveboard loads. Set this property in `spotterChatConfig`. The default value is `true`. Supported in `AppEmbed` and `LiveboardEmbed`. +* `starterPrompts.liveboard` + +Starter prompts for the Spotter chat panel on a Liveboard. + +|[tag greenBackground]#NEW# +a| +[discrete] +===== Action IDs for embedded Spotter and Liveboard interfaces + +The following `Action` enum members are added in this release: + +* `Action.SpotterChatPin` + +Controls the visibility and enabled state of the pin and unpin action in the Spotter conversation edit menu. +* `Action.SpotterAnalystList` + +Controls the visibility and enabled state of the *Show all* Analysts entry in the Analyst interface. +* `Action.SpotterDefaultAnalyst` + +Controls the visibility and enabled state of the default Spotter entry in the Analyst interface. +* `Action.SpotterOnLiveboard` + +Controls the visibility and enabled state of the *Spotter* button in the Liveboard header. +* `Action.AllLiveboardFilters` + +Shows, hides, or greys out all filter surfaces on a Liveboard: filter chips, parameter chips, and cross-filter chips at the Liveboard, tab, and group levels. Parameter and cross-filter chips can only be hidden. +* `Action.EditInputTable` + +Controls the *Edit input table* action, which lets users edit an input table used by an Answer directly from the Liveboard. +* `Action.QuickSearchPill` + +Controls the *Basic Search* starter prompt pill in the Spotter interface. +* `Action.DeepAnalysisPill` + +Controls the *Deep Analysis* starter prompt pill in the Spotter interface. +* `Action.DataLiteracyPill` + +Controls the *Data Literacy* starter prompt pill in the Spotter interface. + +|[tag greenBackground]#NEW# +a| +[discrete] +===== Events + +Embed events:: +* `EmbedEvent.SpotterConversationPinned` + +Emitted when a user pins a Spotter conversation. The event payload includes the `conversationId` and `pinnedAt` values. +* `EmbedEvent.SpotterConversationUnpinned` + +Emitted when a user unpins a Spotter conversation. The event payload includes the `conversationId` and `unpinnedAt` values. + +Host events:: +* `HostEvent.PinSpotterConversation` + +Pins a saved Spotter conversation. Accepts `{ conversationId }`. +* `HostEvent.UnpinSpotterConversation` + +Unpins a previously pinned Spotter conversation. Accepts `{ conversationId }`. +* `HostEvent.GetGroups` + +Returns filter and parameter group details for the current Liveboard. The response includes `orderedGroupIds`, `numberOfGroups`, and `Groups`. +* `HostEvent.OpenParameter` + +Opens the parameter panel for a specific parameter on the Liveboard. Accepts an optional `applicability` object to scope the action to a tab or group. + +The pin and unpin events require `spotterChatPinConfig.enabled: true` and `enablePastConversationsSidebar: true` in the embed configuration. The host events also require chat history to be enabled on your ThoughtSpot instance. + +Updated events:: +The following existing events now include or accept an optional `applicability` attribute, which scopes filters and parameters to a Liveboard tab or group: + +* `EmbedEvent.FilterChanged` +* `EmbedEvent.ParameterChanged` +* `HostEvent.OpenFilter` +* `HostEvent.GetFilters` +* `HostEvent.UpdateFilters` +* `HostEvent.GetParameters` +* `HostEvent.UpdateParameters` + +Deprecated events:: +* `HostEvent.UpdatePersonalizedView` is deprecated. Use `HostEvent.SelectPersonalizedView` instead. `HostEvent.SelectPersonalizedView` additionally accepts an optional `viewName` to select a view by name, resets to the original view when the payload is empty, and reports an error when the named view isn't found. +|==== + == Version 1.52.x, September 2026 [width="100%" cols="1,4"] diff --git a/modules/ROOT/pages/authentication.adoc b/modules/ROOT/pages/authentication.adoc index 106bf6c27..6e72126ab 100644 --- a/modules/ROOT/pages/authentication.adoc +++ b/modules/ROOT/pages/authentication.adoc @@ -153,6 +153,7 @@ __Optional__ |__Nullable__. `ENABLE` or `DISABLE` authentication for a particular Org. When enabled, a new org-level access token is generated if one does not exist. When disabled, the existing org-level access token is revoked. |`org_identifier` +|__String__. Name or ID of the Org for which to enable or disable trusted authentication. Specify this attribute within the `org_preferences` array. |===== @@ -556,6 +557,125 @@ curl -X POST \ If `auto_create` is set to `true` and the username specified in the API request already exists in ThoughtSpot, the `/api/rest/2.0/auth/token/custom` API does not update user properties such as display name, email, Org, or group assignments. ==== +[#multi-org-tokens] +=== Multi-Org tokens [beta betaBackground]^Beta^ +By default, a token authorizes API requests in a single Org. From 26.10.0.cl, ThoughtSpot users with cluster administration privileges can request a token authorized for multiple Orgs by including the optional `scope` object in the token request, and then select the Org for each request using the `X-Org-Selector` header. + +[NOTE] +==== +* This feature is in Beta and is disabled by default. To enable this feature, contact ThoughtSpot Support. +* Only users with cluster administration privileges can generate a multi-Org token. +==== + +==== Supported endpoints + +The `scope` request property is supported on the following token endpoints: + +* `POST /api/rest/2.0/auth/token/full` +* `POST /api/rest/2.0/auth/token/custom` (supports `SPECIFIC_ORGS` only) +* `POST /api/rest/2.0/auth/token/object` + +==== The `scope` request property + +[width="100%" cols="2,4"] +[options="header"] +|===== +|Parameter|Description +|`scope` a|__Object__. Optional. The set of Orgs the token is authorized to operate in, recorded at issuance. Requires cluster administration privileges. Specify the following attributes: + +* `org_scope` + +__String__. Org scope type. Valid values: + +** `SPECIFIC_ORGS`: authorizes the token for the Orgs listed in `org_identifiers`. +** `ALL_MEMBER_ORGS`: authorizes the token for all Orgs the user is a member of. Not supported for custom (ABAC) tokens. + +* `org_identifiers` + +__Array of strings__. ID or name of the Orgs the token is authorized for. Required when `org_scope` is `SPECIFIC_ORGS`; ignored when `org_scope` is `ALL_MEMBER_ORGS`. +|===== + +==== Request example +A multi-Org token request replaces `org_id` with the `scope` object. The issued token is authorized for every Org in the requested set, and each API request selects its target Org with the `X-Org-Selector` header. + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/auth/token/full' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + --data-raw '{ + "username": "tsAdminUser", + "secret_key": "{SECRET_KEY}", + "validity_time_in_sec": 86400, + "scope": { + "org_scope": "SPECIFIC_ORGS", + "org_identifiers": ["1", "2", "5"] + } +}' +---- + +[NOTE] +The `scope` object in a single-Org token response carries no `org_scope` or `org_ids` properties. API requests made with this token always execute in the Org the token was issued for; the `X-Org-Selector` header is not required. + +==== Response properties +When a multi-Org token is issued, the `scope` object in the response includes the following additional properties. + +[source,JSON] +---- +{ + "token": "{AUTH_TOKEN}", + "creation_time_in_millis": 1675129264089, + "expiration_time_in_millis": 1675129564089, + "scope": { + "access_type": "FULL", + "org_id": 1, + "metadata_id": null, + "org_scope": "SPECIFIC_ORGS", + "org_ids": [ + { + "id": 1, + "name": "Org-Finance" + }, + { + "id": 2, + "name": "Org-Sales" + }, + { + "id": 5, + "name": "Org-Marketing" + } + ] + }, + "valid_for_user_id": "59a122dc0-38d7-43e7-bb90-86f724c7b602", + "valid_for_username": "tsAdminUser" +} +---- + +The same properties appear in the `POST /api/rest/2.0/auth/token/validate` response, so API clients can inspect which Orgs an existing token is authorized for. + +[width="100%" cols="2,4"] +[options="header"] +|===== +|Property|Description +|`scope.org_scope`|__String__. Org scope the token is authorized for: `SPECIFIC_ORGS` or `ALL_MEMBER_ORGS`. This property is absent for a legacy single-Org token. +|`scope.org_ids`|__Array__. The Orgs the token is authorized for when `org_scope` is `SPECIFIC_ORGS`. +|===== + +==== Per-request Org selection +Each API request made with a multi-Org token selects one Org from the token's authorized set using the `X-Org-Selector` request header: + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/users/search' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {AUTH_TOKEN}' \ + -H 'X-Org-Selector: 2' \ + --data-raw '{}' +---- + +The header selects an Org from the authority the token already holds; it does not grant access to any Org outside the token's scope. Selecting an Org outside the authorized set fails the request. + === Generating a session token To generate a new authentication token for an existing authenticated session, send a `GET` request to `/api/rest/2.0/auth/session/token`. This endpoint mints a fresh bearer token valid for 24 hours. It does not return the token currently held by the caller's session, but issues a new token derived from the authenticated session context. diff --git a/modules/ROOT/pages/common/nav-embedding.adoc b/modules/ROOT/pages/common/nav-embedding.adoc index dbcec8c9d..8133c24dc 100644 --- a/modules/ROOT/pages/common/nav-embedding.adoc +++ b/modules/ROOT/pages/common/nav-embedding.adoc @@ -11,6 +11,7 @@ Embed ThoughtSpot in a web app * link:{{navprefix}}/getting-started[Get started] * link:{{navprefix}}/embed-ai-search-analytics[Embed Spotter AI Analytics] ** link:{{navprefix}}/embed-spotter[Embed full Spotter experience] +** link:{{navprefix}}/embed-spotter-analyst[Embed a Spotter Analyst] ** link:{{navprefix}}/customize-spotter-embed[Customize Spotter interface] ** link:{{navprefix}}/customize-spotter-chat-experience[Customize chat experience] ** link:{{navprefix}}/customize-spotter-sidebar[Customize sidebar panel] diff --git a/modules/ROOT/pages/common/nav-in-product-help.adoc b/modules/ROOT/pages/common/nav-in-product-help.adoc index 5baf2043f..e2dfb49e3 100644 --- a/modules/ROOT/pages/common/nav-in-product-help.adoc +++ b/modules/ROOT/pages/common/nav-in-product-help.adoc @@ -30,6 +30,7 @@ Embed ThoughtSpot in a web app * link:{{navprefix}}/tsembed[Quickstart guide] * link:{{navprefix}}/embed-ai-search-analytics[Embed Spotter AI Analytics] ** link:{{navprefix}}/embed-spotter[Embed full Spotter experience] +** link:{{navprefix}}/embed-spotter-analyst[Embed a Spotter Analyst] ** link:{{navprefix}}/customize-spotter-embed[Customize Spotter interface] ** link:{{navprefix}}/customize-spotter-chat-experience[Customize chat experience] ** link:{{navprefix}}/customize-spotter-sidebar[Customize sidebar panel] @@ -236,6 +237,7 @@ REST APIs *** link:{{navprefix}}/spotter-agent-sharing-apis[Spotter agent conversation sharing APIs] *** link:{{navprefix}}/spotter-agent-instructions[Spotter AI agent instructions] *** link:{{navprefix}}/spotter-agent-conversation-mgmt-apis[APIs for managing saved conversations] +*** link:{{navprefix}}/spotter-analyst-api[Spotter Analyst APIs] *** link:{{navprefix}}/spotter-memory-migration[Spotter memory migration API] *** link:{{navprefix}}/spotter-apis-classic[AI APIs (Spotter Classic) ^BETA^] *** link:{{navprefix}}/spotter-nl-instructions[Data model instructions APIs ^BETA^] diff --git a/modules/ROOT/pages/common/nav-rest-api.adoc b/modules/ROOT/pages/common/nav-rest-api.adoc index 0251c0f31..60d009d8a 100644 --- a/modules/ROOT/pages/common/nav-rest-api.adoc +++ b/modules/ROOT/pages/common/nav-rest-api.adoc @@ -21,6 +21,7 @@ REST API endpoints ** link:{{navprefix}}/api-user-management[Users and group privileges] ** link:{{navprefix}}/rbac[Role-based access control] ** link:{{navprefix}}/audit-logs[Audit logs] +** link:{{navprefix}}/feature-management[Feature Management] * Multi-tenancy and Orgs ** link:{{navprefix}}/orgs-api-op[Orgs APIs] @@ -37,6 +38,7 @@ REST API endpoints ** link:{{navprefix}}/spotter-agent-sharing-apis[Spotter agent conversation sharing APIs] ** link:{{navprefix}}/spotter-agent-instructions[Spotter AI agent instructions] ** link:{{navprefix}}/spotter-agent-conversation-mgmt-apis[APIs for managing saved conversations] +** link:{{navprefix}}/spotter-analyst-api[Spotter Analyst APIs] ** link:{{navprefix}}/spotter-memory-migration[Spotter memory migration API] ** link:{{navprefix}}/spotter-apis-classic[AI APIs (Spotter Classic)] ** link:{{navprefix}}/spotter-nl-instructions[Data model instructions APIs] diff --git a/modules/ROOT/pages/customize-spotter-analysts.adoc b/modules/ROOT/pages/customize-spotter-analysts.adoc index 2c2a8ad59..9fff0430f 100644 --- a/modules/ROOT/pages/customize-spotter-analysts.adoc +++ b/modules/ROOT/pages/customize-spotter-analysts.adoc @@ -18,7 +18,7 @@ ThoughtSpot allows users to create and manage link:https://docs.thoughtspot.com/ When Spotter Analysts are enabled on your ThoughtSpot instance and xref:customize-spotter-sidebar.adoc[sidebar] is visible in the embedded view, the Analysts panel and dashboard are visible by default. The sidebar also includes the option to view a specific Analyst or open the dashboard to view all the available Analysts. === Customizing the Analyst panel visibility -To control the visibility of the Spotter Analysts panel in the embedded sidebar, use the `SpotterAnalystSidebar` action ID in the `disabledActions` or `hiddenActions` array. +To control the visibility of the Spotter Analysts panel in the embedded sidebar, use the `Action.SpotterAnalystSidebar` action ID in the `disabledActions` or `hiddenActions` array. The following example shows how to hide the Spotter Analysts panel from the embedded view: @@ -26,7 +26,7 @@ The following example shows how to hide the Spotter Analysts panel from the embe ---- const embed = new SpotterEmbed("#embed", { // ...other Spotter embed configuration options - disabledActions: [ + hiddenActions: [ Action.SpotterAnalystSidebar, ], }); @@ -39,19 +39,19 @@ When Analysts are enabled in the embedded view, you can show or hide specific me |=== | Action ID | Description -| `Action.CreateAnalyst` +| `Action.SpotterAnalystCreate` | Action ID for the *Create new* action for creating a new Spotter Analyst. -| `Action.EditAnalyst` +| `Action.SpotterAnalystEdit` | Action ID for the edit option for an existing Analyst. -| `Action.CopyAnalyst` +| `Action.SpotterAnalystMakeACopy` | Action ID for the *Make a copy* action for duplicating an Analyst. -| `Action.ShareAnalyst` +| `Action.SpotterAnalystShare` | Action ID for the share action for sharing an Analyst with other users. -| `Action.DeleteAnalyst` +| `Action.SpotterAnalystDelete` | Action ID for the delete option for removing an Analyst. |=== @@ -60,7 +60,7 @@ When Analysts are enabled in the embedded view, you can show or hide specific me const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { // ...other embed view configuration options hiddenActions: [ - Action.DeleteAnalyst, + Action.SpotterAnalystDelete, ], }); ---- diff --git a/modules/ROOT/pages/customize-spotter-sharing.adoc b/modules/ROOT/pages/customize-spotter-sharing.adoc index 07dfa6676..08400327f 100644 --- a/modules/ROOT/pages/customize-spotter-sharing.adoc +++ b/modules/ROOT/pages/customize-spotter-sharing.adoc @@ -1,8 +1,8 @@ -= Customize conversation sharing experience += Customize conversation sharing options :toc: true :toclevels: 2 -:page-title: Customizing Spotter conversation sharing +:page-title: Customizing Spotter conversation options :page-pageid: customize-spotter-sharing :page-description: You can customize the Spotter conversation sharing experience using the customization options available in the Visual Embed SDK. diff --git a/modules/ROOT/pages/customize-spotter-sidebar.adoc b/modules/ROOT/pages/customize-spotter-sidebar.adoc index 288eee572..63680f829 100644 --- a/modules/ROOT/pages/customize-spotter-sidebar.adoc +++ b/modules/ROOT/pages/customize-spotter-sidebar.adoc @@ -90,7 +90,35 @@ const spotterEmbed = new SpotterEmbed('#ts-embed', { }); ---- -For a complete list of action IDs, see xref:Action.adoc[Action reference]. +[#pinning-conversations] +=== Pinning conversations +Users can pin Spotter conversations in the chat history panel so that the conversations appear at the top of the list. This feature is available from ThoughtSpot Cloud 26.10.0.cl and Visual Embed SDK 1.53.0, and it requires the chat history panel (`enablePastConversationsSidebar: true`). + +Pinning is off by default in embedded Spotter. To turn it on, set the `enabled` property to `true` in the `spotterChatPinConfig` object of `spotterSidebarConfig`. When pinning is off, the *Pin* and *Unpin* options and the pin icon are hidden, and the `HostEvent.PinSpotterConversation` and `HostEvent.UnpinSpotterConversation` events have no effect. + +To customize the labels for the *Pin* and *Unpin* options in the conversation edit menu, set the following properties in the `spotterChatPinConfig` object: + +* `pinLabel` + +__String__. Custom label for the pin option in the conversation edit menu. +* `unpinLabel` + +__String__. Custom label for the unpin option in the conversation edit menu. + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed('#ts-embed', { + // ...other embed view configuration options + spotterSidebarConfig: { + enablePastConversationsSidebar: true, + spotterChatPinConfig: { + enabled: true, // Turn on pinning + pinLabel: 'Pinned', // Custom label for the pin option + unpinLabel: 'Remove Pin', // Custom label for the unpin option + }, + }, +}); +---- + +To pin or unpin conversations programmatically, or to listen for pin events, see <<_customizing_app_interactions,Customizing app interactions>>. For more information, see xref:event-embedEvents.adoc#pin-events[Spotter conversation pin events] and xref:events-hostEvents.adoc#spotter-pin-host-events[Spotter conversation pin and unpin]. === Customizing app interactions Use the following event IDs to enable interaction between the host application and the chat history panel: @@ -98,6 +126,8 @@ Use the following event IDs to enable interaction between the host application a HostEvents:: * `HostEvent.StartNewSpotterConversation` + Starts a new Spotter conversation programmatically. +* `HostEvent.PinSpotterConversation` and `HostEvent.UnpinSpotterConversation` + +Pins or unpins a saved conversation. Both events accept a `conversationId`, and require `spotterChatPinConfig.enabled` to be `true`. + [source,JavaScript] @@ -116,6 +146,8 @@ Emitted when a user renames a conversation from the chat history panel. The even Emitted when a user deletes a conversation from the chat history panel. The event payload includes the `convId` and `title`. * `EmbedEvent.SpotterConversationSelected` + Emitted when a user selects a conversation from the chat history panel. The event payload includes the `convId`, `title`, and `worksheetId`. +* `EmbedEvent.SpotterConversationPinned` and `EmbedEvent.SpotterConversationUnpinned` + +Emitted when a user pins or unpins a conversation. The event payload includes the `conversationId` and the `pinnedAt` or `unpinnedAt` timestamp in ISO 8601 date and time format. + [source,JavaScript] diff --git a/modules/ROOT/pages/data-security.adoc b/modules/ROOT/pages/data-security.adoc index ae6adf312..e8f25e89b 100644 --- a/modules/ROOT/pages/data-security.adoc +++ b/modules/ROOT/pages/data-security.adoc @@ -26,3 +26,14 @@ The OAuth workflow requires opening a new window or redirecting to the OAuth pro CLS restricts user access to specific columns of a table. When CLS is applied, users see only the columns that they are allowed to view. Object owners can configure CLS by sharing a relevant set of columns in a table with a specific user or user group. For more information on CLS, see link:https://docs.thoughtspot.com/cloud/latest/share-source-tables[Sharing tables and columns, window=_blank]. + +[#csr-liveboards] +=== Column security rules (CSR) on Liveboards +Starting with ThoughtSpot Cloud 26.10.0.cl, Liveboards that include columns restricted by Column Security Rules (CSR) open and work normally for users who cannot access those columns, including in embedded Liveboards. Previously, such Liveboards were blocked for these users. Column security remains fully enforced: + +* Filter chips from columns that the user cannot access are masked instead of blocking the Liveboard. Only one masked filter chip is shown, at the end of the filter bar, to indicate that one or more filters are inaccessible. For example, if five filters are inaccessible, the Liveboard still shows a single masked filter chip. +* Scheduled Liveboard deliveries apply CSR separately for each recipient. + +To control whether masked filter chips are visible in an embedded Liveboard, use the `showMaskedFilterChip` SDK property. For more information, see xref:embed-pinboard.adoc#masked-filter-chips[Masked filter chips]. + +For more information, see link:https://docs.thoughtspot.com/cloud/latest/security-data-object#csr-liveboard[Column security rules on Liveboards, window=_blank]. diff --git a/modules/ROOT/pages/deprecated-features.adoc b/modules/ROOT/pages/deprecated-features.adoc index a6f33608b..b5b15af48 100644 --- a/modules/ROOT/pages/deprecated-features.adoc +++ b/modules/ROOT/pages/deprecated-features.adoc @@ -14,6 +14,7 @@ As ThoughtSpot applications evolve, some existing features will be deprecated an [options='header'] |===== |Feature|Impacted interface and release versions|Deprecation date |End of Support / removal from the product +a|xref:deprecated-features.adoc#IAMv1[IAMv1] a| ThoughtSpot Cloud 26.12.0.cl and later |December 2026 | December 2026 a|xref:deprecated-features.adoc#liveboardDiscoverable[Liveboard and answer discoverability] a|ThoughtSpot Cloud 26.2.0.cl and later | February 2026 | August 2026 a|xref:deprecated-features.adoc#everynmins[Minute-level schedule frequency] @@ -42,11 +43,6 @@ a|REST API v2 + * ThoughtSpot Cloud 10.4.0.cl and later|November 2024 a| September 2025 -|xref:deprecated-features.adoc#IAMv1[IAMv1] a| - -* ThoughtSpot Cloud 10.8.0.cl and later - -|November 2024 | June 2025 __(tentative)__ |xref:deprecated-features.adoc#_search_assist[Search Assist] a| * Application UI and Visual Embed Playground + @@ -274,10 +270,10 @@ Note that the `connection_identifier` in both these endpoints is a path paramete [#IAMv1] == IAMv1 -Identity and Access Management (IAMv1) will be deprecated for all ThoughtSpot embedded customers tentatively in 10.8.0.cl. IAMv2 will be enabled on ThoughtSpot instances during maintenance windows from 10.4.0.cl onwards. +Identity and Access Management (IAMv1) will be deprecated for all ThoughtSpot embedded customers. Effective from:: -* ThoughtSpot Cloud 10.8.0.cl +* ThoughtSpot Cloud 26.12.0.cl === Recommended action diff --git a/modules/ROOT/pages/embed-pinboard.adoc b/modules/ROOT/pages/embed-pinboard.adoc index 3d1618160..4c47759b8 100644 --- a/modules/ROOT/pages/embed-pinboard.adoc +++ b/modules/ROOT/pages/embed-pinboard.adoc @@ -264,6 +264,23 @@ When `hideIrrelevantChipsInLiveboardTabs` is `true`: * A *Show irrelevant filters* toggle button appears in the filter row when at least one chip is hidden, allowing users to temporarily reveal all chips. * When the user clicks *Show irrelevant filters*, a complementary *Hide irrelevant filters* button appears to restore the filtered view. +[#masked-filter-chips] +==== #Masked filter chips# +#If a Liveboard includes filters on columns that a user cannot access because of column-level security, the filter values are masked for that user. Use the `showMaskedFilterChip` property to control whether these masked filter chips are visible:# + +* #`true`: the filter chips for inaccessible columns are displayed as masked.# +* #`false`: the filter chips for inaccessible columns are hidden.# + +[source,JavaScript] +---- +const liveboardEmbed = new LiveboardEmbed(document.getElementById('ts-embed'), { + //... other embed config properties + showMaskedFilterChip: true, +}); +---- + +#The `showMaskedFilterChip` property is also available in full application embedding. For more information, see xref:data-security.adoc#csr-liveboards[Column security rules on Liveboards].# + [#noteTiles] === Add Note tiles You can add a link:https://docs.thoughtspot.com/cloud/latest/liveboard-notes[Liveboard Note tile, window=_blank] with custom text, images, and links on an embedded Liveboard. @@ -329,11 +346,6 @@ see xref:customize-css-styles.adoc#liveboard-layout-vars[Liveboard layout CSS va === Liveboard browser cache and refresh ThoughtSpot supports browser-side data caching for Liveboards to improve load performance for users who revisit the same Liveboard within a session. Users can clear cache by clicking the refresh icon in the Liveboard header. -[NOTE] -==== -Liveboard browser cache and refresh is an Early Access feature and is disabled by default on ThoughtSpot instances. To enable this feature on your instance, contact ThoughtSpot support. -==== - To enable Liveboard data caching, set `enableLiveboardDataCache` to `true`. [source,javascript] @@ -384,6 +396,59 @@ limit are silently dropped without an error or warning. For more information, se xref:runtime-filters.adoc#_maximum_filter_count[Runtime filter limit]. ==== +[#contextual-liveboard-filtering] +==== Contextual filtering in Liveboards [earlyAccess eaBackground]#Early Access# +Starting with ThoughtSpot Cloud 26.10.0.cl release, Liveboard filters and parameters can be scoped at three levels: + +* *Liveboard*: applies to all visualizations on the Liveboard. +* *Tab*: applies only to visualizations on a specific tab. +* *Group*: applies only to visualizations in a specific group on a tab. + +With contextual filtering, you can add the same filter at more than one level on a Liveboard, but not at a level directly below it in the same hierarchy. For example: + +* If a `Region` filter is set at the Liveboard level, it cannot be added again on any tab or group on that Liveboard. +* If a `City` filter is set on Tab 1, it cannot be added to a group on Tab 1. However, it can be added to a group on another tab, such as Tab 2, because that group is not in the Tab 1 hierarchy. + +[NOTE] +==== +Contextual filtering in Liveboards is an Early Access feature and is disabled by default on ThoughtSpot instances. To enable this feature on your instance, set `isScopedLiveboardFilteringEnabled` to `true`. +==== + + +[source,JavaScript] +---- +const liveboardEmbed = new LiveboardEmbed(document.getElementById('ts-embed'), { + //... other embed config properties + liveboardId: "d7a5a08e-a1f7-4850-aeb7-0764692855b8", + isScopedLiveboardFilteringEnabled: true, +}); +---- + +The `isScopedLiveboardFilteringEnabled` property is also available in `AppViewConfig` for full application embedding. + +To get the groups on a Liveboard, use `HostEvent.GetGroups`. To scope a filter or parameter update to a specific tab or group, pass the `applicability` attribute with `HostEvent.UpdateFilters` or `HostEvent.UpdateParameters`: + +[source,javascript] +---- +liveboardEmbed.trigger(HostEvent.UpdateFilters, { + filters: [ + { + column: 'Region', + oper: 'IN', + values: ['West'], + applicability: { + level: 'GROUP', + targetId: '{group-id}', + }, + }, + ], +}); +---- + +To listen for filter and parameter changes, use `EmbedEvent.FilterChanged` and `EmbedEvent.ParameterChanged`. Starting with SDK 1.53.0, both events include an optional `applicability` field in their response payload that indicates the scope of the change. + +For more information, see xref:events-hostEvents.adoc#liveboard-group-events[Liveboard group and parameter events] and xref:events-hostEvents.adoc#applicability-host-events[Scoped filter and parameter host events]. + ==== Updating filters Use the following host events in the Visual Embed SDK to update filters: diff --git a/modules/ROOT/pages/embed-spotter-analyst.adoc b/modules/ROOT/pages/embed-spotter-analyst.adoc new file mode 100644 index 000000000..ad3f5772e --- /dev/null +++ b/modules/ROOT/pages/embed-spotter-analyst.adoc @@ -0,0 +1,398 @@ += Embed Spotter Analyst +:toc: true +:toclevels: 2 + +:page-title: Embed Spotter Analyst +:page-pageid: embed-spotter-analyst +:page-description: Embed a single, pinned Spotter Analyst in your app using the Visual Embed SDK + +ThoughtSpot Spotter Analysts are governed AI agents configured with specific data sources, instructions, and starter prompts. Using the Visual Embed SDK, you can embed a single Analyst in your app. This locks the experience to that Analyst, so users get consistent, governed answers without choosing a data source or another Analyst. + +This page shows how to embed one Analyst using the `SpotterEmbed` component. + +== Before you begin + +Before you embed an Analyst, make sure that you have the following: + +* Your ThoughtSpot instance is on version 26.10.0.cl or later. Embedding a Spotter Analyst also requires Visual Embed SDK version 1.53.0 or later. +* GUID of the Analyst to embed. You can copy the GUID from the URL of the Spotter Analyst page or find the GUID using the xref:spotter-analyst-api.adoc#search-analysts[search Analysts] API endpoint. +* GUID of the data model to use for queries. You can use the model that the Analyst is already configured with. If the Analyst spans multiple models, you need the GUID of each model. +* Access for the users who see the embed. Users must have access to the Analyst and its data sources. To grant access, share the Analyst with the users or groups. To share an Analyst programmatically, see xref:spotter-analyst-api.adoc#share-analyst[Share an Analyst]. +* Your embedding app's domain in the Content Security Policy (CSP) Visual Embed hosts and Cross-Origin Resource Sharing (CORS) allowlists. For more information, see xref:security-settings.adoc[Security settings]. + +== Import the SDK components + +Import the `SpotterEmbed` SDK library and the required components into your app environment: + +**npm** +[source,JavaScript] +---- +import { + SpotterEmbed, + AuthType, + init, + Action, +} from '@thoughtspot/visual-embed-sdk'; +---- + +**ES6** +[source,JavaScript] +---- + +---- + +In server-side rendered frameworks such as Next.js, Nuxt, and SvelteKit, the SDK reads `window` when it's imported. To avoid window reference errors, import the SDK dynamically: + +[source,JavaScript] +---- +const { init, SpotterEmbed, AuthType, Action } = + await import('@thoughtspot/visual-embed-sdk'); +---- + +== Configure the host URL and authentication method + +Specify the ThoughtSpot host URL in `thoughtSpotHost` and the authentication type in `authType`. For testing purposes, you can use `AuthType.None`, which uses the browser's existing ThoughtSpot session. For information about other authentication options, see xref:embed-authentication.adoc[Authentication]. + +[source,JavaScript] +---- +init({ + thoughtSpotHost: 'https://{cluster}', // Replace with your ThoughtSpot application URL + authType: AuthType.None, // Use the appropriate AuthType for your setup +}); +---- + +== Specify the Analyst and data source to embed + +Create an instance of the `SpotterEmbed` object, and pin it to one Analyst by using `spotterAnalystConfig.analystId`. + +The `analystId` is the GUID of the Analyst to embed. When you specify it, the embed opens with this Analyst and doesn't show the default Spotter or the *Show all* Analysts list. + +Optionally, specify the data source that Spotter queries: + +* `worksheetId` + +GUID of the model to query. Include it alongside `analystId`. +* `dataSources` + +Array that contains one GUID for each model, for an Analyst that spans multiple models. If you set both `dataSources` and `worksheetId`, `dataSources` takes precedence. + +The following example embeds one Analyst that uses a single model: + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { + frameParams: { width: '100%', height: '100%' }, + worksheetId: '{model-guid}', + + // Specify the Analyst ID + spotterAnalystConfig: { + analystId: '{analyst-guid}', + }, +}); +---- + +If the Analyst spans multiple models, use `dataSources` instead of `worksheetId`: + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { + frameParams: { width: '100%', height: '100%' }, + dataSources: ['{model-guid-1}', '{model-guid-2}'], + + // Specify the Analyst ID + spotterAnalystConfig: { + analystId: '{analyst-guid}', + }, +}); +---- + +== Customize the Analyst interface + +You can customize the following aspects of the embedded Analyst interface: + +* <<_hiding_the_analyst_switcher_and_edit_controls,Hiding the Analyst switcher and edit controls>> +* <<_customizing_sidebar_visibility,Customizing sidebar visibility>> +* <<_customizing_the_chat_interface,Customizing the chat interface>> +* <<_customizing_styles_and_themes,Customizing styles and themes>> +* <<_customizing_app_interactions,Customizing app interactions>> + +=== Hiding the Analyst switcher and edit controls + +To make sure that users can't switch to another Analyst or to the default Spotter, hide the relevant controls by using the following action IDs in `hiddenActions`: + +* `Action.SpotterAnalystSidebar` + +Hides the Analyst selection panel in the sidebar. +* `Action.SpotterDefaultAnalyst` + +Hides the default Spotter entry in the Analyst selection panel. +* `Action.SpotterAnalystList` + +Hides the *Show all* Analysts entry in the Analyst selection panel. + +To hide the Analyst authoring controls, use the following action IDs in `hiddenActions`: + +* `Action.SpotterAnalystCreate` + +Hides the *Create* action in the Analyst interface. +* `Action.SpotterAnalystEdit` + +Hides the *Edit* action in the Analyst interface. +* `Action.SpotterAnalystDelete` + +Hides the *Delete* action in the Analyst interface. +* `Action.SpotterAnalystMakeACopy` + +Hides the *Make a copy* action in the Analyst interface. +* `Action.SpotterAnalystShare` + +Hides the *Share* action in the Analyst interface. + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { + // ...other embed view configuration options + + // Hide the controls that let users switch Analysts and edit them + hiddenActions: [ + Action.SpotterAnalystSidebar, + Action.SpotterDefaultAnalyst, + Action.SpotterAnalystList, + Action.SpotterAnalystCreate, + Action.SpotterAnalystEdit, + Action.SpotterAnalystDelete, + Action.SpotterAnalystMakeACopy, + Action.SpotterAnalystShare, + ], +}); +---- + +[IMPORTANT] +==== +Hiding a control removes it from the interface, but it doesn't restrict what users can do. To enforce data security and governance, use data security rules and object sharing permissions. +==== + +=== Customizing sidebar visibility + +To show only one Analyst without a chat history sidebar, set `enablePastConversationsSidebar` to `false` in the `spotterSidebarConfig` object. + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { + // ...other embed view configuration options + + // Turn the chat history sidebar off explicitly + spotterSidebarConfig: { + enablePastConversationsSidebar: false, + }, +}); +---- + +If a narrow sidebar rail remains visible, for example an expand toggle, a *New chat* icon, or a footer, hide the sidebar shell by adding the following action IDs to `hiddenActions`. These action IDs are available from ThoughtSpot Cloud 26.3.0.cl. + +* `Action.SpotterSidebarHeader` + +Hides the sidebar title and toggle button. +* `Action.SpotterSidebarToggle` + +Hides the sidebar expand and collapse button. +* `Action.SpotterNewChat` + +Hides the *New chat* button. +* `Action.SpotterSidebarFooter` + +Hides the sidebar footer, which includes the documentation link. +* `Action.SpotterDocs` + +Hides only the documentation or best practices link in the sidebar footer. + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { + // ...other embed view configuration options + + // Hide the Analyst switcher and the sidebar shell + hiddenActions: [ + Action.SpotterAnalystSidebar, + Action.SpotterDefaultAnalyst, + Action.SpotterAnalystList, + Action.SpotterSidebarHeader, + Action.SpotterSidebarToggle, + Action.SpotterNewChat, + Action.SpotterSidebarFooter, + ], +}); +---- + +If you want to keep the chat history sidebar, with its expand toggle and *New chat* button, set `enablePastConversationsSidebar` to `true` and hide only the Analyst controls described in the previous section. + +To customize the actions available for saved chats and conversation sharing, see xref:customize-spotter-sidebar.adoc#_customizing_sidebar_menu_actions[Customizing the Spotter sidebar panel] and xref:customize-spotter-sharing.adoc[Customizing conversation sharing options]. + +=== Customizing the chat interface + +If you want to show only the chat interface, without extra options such as starter prompts or a data source selector, use the options described in the following sections. + +==== Hiding the data source selector + +To keep users on the data source that you specify, set `hideSourceSelection` to `true`. This hides the data source selector. To show the selected data source but prevent users from changing it, set `disableSourceSelection` to `true` instead. + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { + // ...other embed view configuration options + + // Hide the data source selector + hideSourceSelection: true, +}); +---- + +==== Hiding chat interface controls + +To hide other controls in the chat interface, use the following action IDs in `hiddenActions`: + +* `Action.SpotterChatConnectors` + +Hides the connectors in the chat interface. +* `Action.SpotterChatModeSwitcher` + +Hides the mode switcher in the chat interface. +* `Action.SpotterFeedback` + +Hides the feedback widget. + +==== Customizing starter prompt pills + +Starter prompts are suggested questions that appear as pills near the chat input area. You can show them, change their labels and questions as needed, or hide them from the chat interface. + +Starter prompts are off by default. To turn them on, set `enable` to `true` in the `starterPrompts` object of `spotterChatConfig`. Then use the `starterPrompts` options to customize the pills and their labels. + +To show or hide individual prompt pills, use `hiddenActions` with the following action IDs: + +* `Action.QuickSearchPill` for the *Quick search* pill +* `Action.DeepAnalysisPill` for the *Deep analysis* pill +* `Action.DataLiteracyPill` for the *Know your data* pill + +[source,JavaScript] +---- +const spotterEmbed = new SpotterEmbed(document.getElementById('ts-embed'), { + // ...other embed view configuration options + spotterChatConfig: { + starterPrompts: { + enable: true, + quick: { + label: 'Common questions', + questions: [ + { + label: 'Top products', + prompt: 'What are the top products by revenue?', + }, + ], + }, + }, + }, + // Hide the Deep analysis and Know your data pills + hiddenActions: [Action.DeepAnalysisPill, Action.DataLiteracyPill], +}); +---- + +For more information, see xref:customize-spotter-chat-experience.adoc#_spotter_starter_prompts[Customizing the Spotter chat experience]. + +=== Customizing styles and themes + +To customize the styles and theme of the embedded Spotter Analyst to match your app's branding, use the xref:css-customization.adoc[CSS customization framework]. + +=== Customizing app interactions + +To listen to the events emitted by the embedded ThoughtSpot component, use the xref:event-embedEvents.adoc[embed event] handlers. + +To allow your app to trigger actions in the embedded ThoughtSpot component, use the xref:events-hostEvents.adoc[host events]. + +== Render the embedded object + +[source,JavaScript] +---- +spotterEmbed.render(); +---- + +== Code sample + +[source,JavaScript] +---- +import { + SpotterEmbed, + AuthType, + init, + Action, +} from '@thoughtspot/visual-embed-sdk'; + +// Initialize the ThoughtSpot Visual Embed SDK with your ThoughtSpot URL and authentication type. +init({ + thoughtSpotHost: 'https://{cluster}', // Replace with your ThoughtSpot application URL + authType: AuthType.None, // Use the appropriate AuthType for your setup +}); + +// Find the container element in your HTML where the SpotterEmbed will be rendered. +const container = document.getElementById('ts-embed'); +if (container) { + // Create and configure the SpotterEmbed + const spotterEmbed = new SpotterEmbed(container, { + frameParams: { + height: '100%', // Set the height of the embedded frame + width: '100%', // Set the width of the embedded frame + }, + + // ID of the model to query. For an Analyst that spans multiple models, + // use dataSources: ['{model-guid-1}', '{model-guid-2}'] instead. + worksheetId: '{model-guid}', + + // Specify the Analyst ID + spotterAnalystConfig: { analystId: '{analyst-guid}' }, + + // Turn the chat history sidebar off explicitly + spotterSidebarConfig: { enablePastConversationsSidebar: false }, + + // Hide the controls that switch Analysts + hiddenActions: [ + Action.SpotterAnalystSidebar, + Action.SpotterDefaultAnalyst, + Action.SpotterAnalystList, + ], + + // Hide the data source selector + hideSourceSelection: true, + }); + + // Render the SpotterEmbed in the container. + spotterEmbed.render(); +} +---- + +== Verify your embed + +* Load the embedded object. + +If the embedding is successful, you'll see the Spotter page for the Analyst that you pinned. +* Verify that the Analyst switcher is hidden and that users can't open another Analyst or the default Spotter. +* Start a chat session, ask a question, and view the results. +* Verify that the customization settings are applied. + +If you see a blank screen or an error, see <>. + +[#troubleshooting] +== Troubleshooting + +[cols="2,3"] +|==== +| Issue | Resolution + +| The embed doesn't load because of a CSP or CORS error +| Add your host app origin to the CSP Visual Embed hosts and CORS allowlists. An entry matches the whole origin, including the port. For the valid domain formats, see xref:security-settings.adoc#port-protocol[Security settings]. + +| A ThoughtSpot login form appears, or the embed spins with no error +| There is no session. Check the network tab for a `401` response from `/callosum/v1/session/info`. If you use `AuthType.None`, sign in to the ThoughtSpot instance in another tab. For production instances, ThoughtSpot recommends token-based trusted authentication. For more information, see xref:embed-authentication.adoc[Embed authentication]. + +| The data source or Analyst can't be found +| Check that the user is signed in to the correct Org, and that the user has view access to the Analyst and its data model. + +| The embed doesn't open the Analyst +| Check that the embed has the correct Analyst GUID, and that your ThoughtSpot instance is on version 26.10.0.cl or later. +|==== + +== Additional resources + +* xref:spotter-analyst-api.adoc[Spotter Analyst API] +* xref:customize-spotter-analysts.adoc[Configure Spotter Analysts] +* xref:customize-spotter-embed.adoc[Customize Spotter embed] +* xref:customize-spotter-chat-experience.adoc[Customizing the Spotter chat experience] +* xref:customize-spotter-sidebar.adoc[Customizing the Spotter sidebar panel] +* xref:event-embedEvents.adoc[Embed events reference] +* xref:events-hostEvents.adoc[Host events reference] +* xref:embed-spotter.adoc[Embed Spotter experience] diff --git a/modules/ROOT/pages/event-embedEvents.adoc b/modules/ROOT/pages/event-embedEvents.adoc index 6b7655f0f..d8162285c 100644 --- a/modules/ROOT/pages/event-embedEvents.adoc +++ b/modules/ROOT/pages/event-embedEvents.adoc @@ -290,8 +290,78 @@ image::./images/embed-event-playground.png[Try Embed event in Playground] == Event enumerations and examples For information about the supported event objects and examples, see xref:EmbedEvent.adoc[EmbedEvent]. +[#pin-events] +=== Spotter conversation pin events + +The following `EmbedEvent` members are available from ThoughtSpot Cloud 26.10.0.cl and Visual Embed SDK 1.53.0. Both events require `spotterChatPinConfig.enabled: true` and `enablePastConversationsSidebar: true` in the embed configuration. + +[cols="1,1,3"] +|=== +| Event | Cluster version | Description + +| `EmbedEvent.SpotterConversationPinned` +| 26.10.0.cl +| Emitted when a user pins a Spotter conversation. Payload: `{ conversationId, pinnedAt }`. + +| `EmbedEvent.SpotterConversationUnpinned` +| 26.10.0.cl +| Emitted when a user unpins a Spotter conversation. Payload: `{ conversationId, unpinnedAt }`. +|=== + +.Listen for pin and unpin events +[source,javascript] +---- +const embed = new SpotterEmbed(container, { + spotterSidebarConfig: { + enablePastConversationsSidebar: true, + spotterChatPinConfig: { enabled: true }, + }, + // ... +}); + +embed.on(EmbedEvent.SpotterConversationPinned, (event) => { + const { conversationId, pinnedAt } = event.data; + console.log(`Conversation ${conversationId} pinned at ${pinnedAt}`); +}); + +embed.on(EmbedEvent.SpotterConversationUnpinned, (event) => { + const { conversationId, unpinnedAt } = event.data; + console.log(`Conversation ${conversationId} unpinned at ${unpinnedAt}`); +}); + +embed.render(); +---- + +[#applicability-scope] +=== Scoped filter and parameter events + +The following `EmbedEvent` members gained an optional `applicability` attribute in SDK 1.53.0. This attribute scopes a filter or parameter change notification to a specific Liveboard tab or group. + +[cols="1,3"] +|=== +| Event | Change in SDK 1.53.0 + +| `EmbedEvent.FilterChanged` +| Payload gains an optional `applicability` object describing the scope of the changed filter. + +| `EmbedEvent.ParameterChanged` +| Payload gains an optional `applicability` object describing the scope of the changed parameter. +|=== + +The `applicability` object has the following shape: + +[source,json] +---- +{ + "level": "LIVEBOARD" | "TAB" | "GROUP", + "targetId": "{tab-or-group-id}" +} +---- + +`targetId` is optional. Omit it when `level` is `LIVEBOARD`. + + == Additional resources * See the xref:EmbedEvent.adoc[EmbedEvent] and xref:HostEvent.adoc[HostEvent] SDK documentation. * For information about triggering events on React components, see xref:react-components_lesson-04.adoc[Event listeners for React components]. - diff --git a/modules/ROOT/pages/events-hostEvents.adoc b/modules/ROOT/pages/events-hostEvents.adoc index 3016a3500..20272105c 100644 --- a/modules/ROOT/pages/events-hostEvents.adoc +++ b/modules/ROOT/pages/events-hostEvents.adoc @@ -184,6 +184,11 @@ Updates the filters applied on an embedded Liveboard. For more information and e ==== HostEvent.OpenFilter Opens the filter panel for the specified column. For more information and examples, see xref:HostEvent.adoc#_openfilter[HostEvent reference documentation]. +[NOTE] +==== +Starting with SDK 1.53.0, the `EmbedEvent.FilterChanged` and `EmbedEvent.ParameterChanged` events include an optional `applicability` field in their response payload. This field describes the scope (Liveboard, tab, or group) of the filter or parameter change that triggered the event. +==== + ==== HostEvent.UpdateRuntimeFilters xref:runtime-filters.adoc[Runtime filters] are applied at runtime, that is, when loading the embedded ThoughtSpot content. Runtime filters can also be updated after the load time using `HostEvent.UpdateRuntimeFilters`. You can add a UI option or button in your embedding app and assign `HostEvent.UpdateRuntimeFilters` to a button to trigger the event when that button is clicked. @@ -351,9 +356,124 @@ liveboardEmbed.trigger(HostEvent.OpenAddFilterModal); ---- When `AddFilter` is in `disabledActions`, `HostEvent.OpenAddFilterModal` is blocked. +[#spotter-pin-host-events] +=== Spotter conversation pin and unpin + +The following `HostEvent` members are available from ThoughtSpot Cloud 26.10.0.cl and Visual Embed SDK 1.53.0. Both events require `enablePastConversationsSidebar: true` in the embed configuration. + +[cols="1,1,3"] +|=== +| Event | Cluster version | Description + +| `HostEvent.PinSpotterConversation` +| 26.10.0.cl +| Pins a saved Spotter conversation. Accepts `{ conversationId }`. + +| `HostEvent.UnpinSpotterConversation` +| 26.10.0.cl +| Unpins a previously pinned Spotter conversation. Accepts `{ conversationId }`. +|=== + +.Programmatically pin a conversation +[source,javascript] +---- +embed.trigger(HostEvent.PinSpotterConversation, { + conversationId: '{conversation-id}', +}); +---- + +[#liveboard-group-events] +=== #Liveboard group and parameter events# + +The following `HostEvent` members are new in SDK 1.53.0 and support the scoped Liveboard filtering feature introduced in ThoughtSpot Cloud 26.10.0.cl. + +[cols="1,3"] +|=== +| Event | Description + +| `HostEvent.GetGroups` +| Returns filter and parameter group details for the current Liveboard. Response includes `orderedGroupIds`, `numberOfGroups`, and `Groups`. + +| `HostEvent.OpenParameter` +| Opens the parameter panel for a specific parameter on the Liveboard. Accepts an optional `applicability` object to scope the action to a tab or group. +|=== + +Use `HostEvent.GetGroups` to retrieve the group IDs needed before scoping a filter or parameter update. The response payload has the following shape: + +[source,json] +---- +{ + "orderedGroupIds": ["{group-id-1}", "{group-id-2}"], + "numberOfGroups": 2, + "Groups": { + "{group-id-1}": { "name": "Sales Overview" }, + "{group-id-2}": { "name": "Regional Breakdown" } + } +} +---- + +[#applicability-host-events] +=== #Scoped filter and parameter host events# + +The following existing `HostEvent` members gained an optional `applicability` attribute in Visual Embed SDK 1.53.0. This attribute scopes a filter or parameter operation to a specific Liveboard tab or group. + +[cols="1,3"] +|=== +| Event | Change in SDK 1.53.0 + +| `HostEvent.OpenFilter` +| Accepts an optional `applicability` parameter to scope which filter panel opens. + +| `HostEvent.GetFilters` +| Returned Liveboard filter objects now include an optional `applicability` field. + +| `HostEvent.UpdateFilters` +| Accepts an optional `applicability` value per filter to scope the update to a tab or group. + +| `HostEvent.UpdateParameters` +| Accepts an optional `applicability` value per parameter to scope the update to a tab or group. + +| `HostEvent.GetParameters` +| Returned parameter objects now include an optional `applicability` field. +|=== + +The `applicability` object has the following shape: + +[source,json] +---- +{ + "level": "LIVEBOARD" | "TAB" | "GROUP", + "targetId": "{tab-or-group-id}" +} +---- + +`targetId` is optional. Omit it when `level` is `LIVEBOARD`. + +The following example shows the typical workflow: retrieve group IDs using `HostEvent.GetGroups`, then pass a group ID in the `applicability` attribute of `HostEvent.UpdateFilters` to scope the filter update to that group only. + +[source,javascript] +---- +// Step 1: retrieve group details for the Liveboard +const groupsResponse = await liveboardEmbed.trigger(HostEvent.GetGroups); +const targetGroupId = groupsResponse.orderedGroupIds[0]; + +// Step 2: apply a filter scoped to that group +liveboardEmbed.trigger(HostEvent.UpdateFilters, { + filters: [ + { + column: 'Region', + oper: 'IN', + values: ['West'], + applicability: { + level: 'GROUP', + targetId: targetGroupId, + }, + }, + ], +}); +---- == Related resources * See xref:EmbedEvent.adoc[EmbedEvent] and xref:HostEvent.adoc[HostEvent] SDK documentation. * For information about triggering events on React components, see xref:react-components_lesson-04.adoc[Event listeners for React components]. - diff --git a/modules/ROOT/pages/feature-management-api.adoc b/modules/ROOT/pages/feature-management-api.adoc new file mode 100644 index 000000000..774e656e0 --- /dev/null +++ b/modules/ROOT/pages/feature-management-api.adoc @@ -0,0 +1,349 @@ += Feature Management +:toc: true +:toclevels: 2 +:page-title: Feature Management API +:page-pageid: feature-management +:page-description: Search feature configurations, assign features to Orgs, and set feature values using the REST API + +The Feature Management API lets Cluster and Org admins retrieve feature configurations, assign features to Orgs, and set feature values programmatically. These endpoints replicate the feature management capabilities available in the link:https://docs.thoughtspot.com/cloud/latest/admin-portal-2#_feature_management[new Admin portal UI, window=_blank]. + +All endpoints are under `/api/rest/2.0/configurations/features/` and are available from ThoughtSpot Cloud 26.10.0.cl. + +== Before you begin + +=== Required privileges + +All Feature Management API endpoints require the `ADMINISTRATION` or `ORG_ADMINISTRATION` privilege. The `ORG_ADMINISTRATION` privilege applies only to Org admins. +If xref:roles.adoc[Role-Based Access Control (RBAC)] is enabled on your instance, these privileges are granted through roles. + +=== Prerequisites + +* Feature Management must be enabled on your ThoughtSpot instance. If it is not enabled, the API returns a `404` error. +* To set a feature value at `ORG` scope, the Org must be assigned to that feature. Otherwise, the API returns a `403` error. To assign Orgs to a feature, see <<_update_feature_assignments,Update feature assignments>>. + +=== Feature scope + +Feature configurations exist at two levels: + +Cluster scope:: The Cluster-level default, visible to Cluster admins. Returns `assigned_orgs` and `is_org_aware` for each feature. +Org scope:: A per-Org value override, visible to Org admins. Returns `element_type`, `element_config`, and `element_value` for each feature. + +=== Feature identifiers + +Each feature can be referenced by its: + +* `feature_name`: a human-readable name, such as `index_columns`. +* `feature_id`: the underlying system identifier, such as `feature.search.columnIndexing`. + +Both forms are accepted in requests to any endpoint that takes a `feature_identifier`. + +=== Feature categories + +Features are grouped into availability categories: + +* `GENERAL_ACCESS`: generally available features. This is the default. +* `EARLY_ACCESS`: features in early access. + +== Search features + +The `POST /api/rest/2.0/configurations/features/search` API endpoint returns the feature configurations available on the ThoughtSpot instance. Requires the `ADMINISTRATION` or `ORG_ADMINISTRATION` privilege. Org admins with the `ORG_ADMINISTRATION` privilege can call this endpoint only with `scope` set to `ORG`. + +A successful request returns `200 OK` and an array of feature groups. Each group contains a `feature_group` name and a `features` array. The fields returned for each feature depend on the `scope` of the request. For more information, see <<_feature_scope,Feature scope>>. + +=== Request parameters + +[cols="1,1,1,3"] +|=== +| Parameter | Type | Required | Description + +| `scope` +| string +| Required +| `CLUSTER` returns the Cluster-admin view, including `assigned_orgs` per feature, and requires the `ADMINISTRATION` privilege. `ORG` returns the Org-admin view, including `element_value` per feature. + +| `org_identifier` +| integer +| Conditional +| Numeric ID of the Org to scope the search to. Required when `scope` is `ORG`; ignored when `scope` is `CLUSTER`. + +| `category` +| string +| Optional +| Feature availability category: `GENERAL_ACCESS` (default) or `EARLY_ACCESS`. +|=== + +=== Example request: Cluster view + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/configurations/features/search' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "scope": "CLUSTER", + "category": "GENERAL_ACCESS" +}' +---- + +=== API response: Cluster view + +[source,json] +---- +[ + { + "feature_group": "search", + "docs_url": null, + "features": [ + { + "feature_id": "feature.search.columnIndexing", + "feature_name": "index_columns", + "assigned_orgs": [ + { + "org_id": 0, + "org_name": "Primary" + } + ], + "is_org_aware": true, + "feature_value": null, + "docs_url": null + } + ] + } +] +---- + +=== Example request: Org view + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/configurations/features/search' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "scope": "ORG", + "org_identifier": 1, + "category": "GENERAL_ACCESS" +}' +---- + +=== API response: Org view + +[source,json] +---- +[ + { + "feature_group": "spotter", + "docs_url": null, + "features": [ + { + "feature_id": "feature.spotter.liveboardAssist", + "feature_name": "spotter_on_liveboard", + "assigned_orgs": null, + "is_org_aware": null, + "feature_value": null, + "element_type": "toggle", + "element_config": null, + "element_value": "true", + "docs_url": null + } + ] + }, + { + "feature_group": "downloads", + "docs_url": null, + "features": [ + { + "feature_id": "feature.export.fileInstructions", + "feature_name": "downloaded_file_instructions", + "assigned_orgs": null, + "is_org_aware": null, + "feature_value": null, + "element_type": "input", + "element_config": { + "type": "textarea" + }, + "element_value": "Internal use only", + "docs_url": null + } + ] + } +] +---- + +== Update feature assignments + +The `POST /api/rest/2.0/configurations/features/assignments/update` API endpoint updates the Org assignments for a feature. Available to Cluster admins only. Org admins cannot call this endpoint. Requires the `ADMINISTRATION` privilege. + +A successful request returns `200 OK` and a `FeatureAssignmentResponse` object with `feature_id`, `feature_name`, and the updated `assigned_orgs` list. + +=== Request parameters + +[cols="1,1,1,3"] +|=== +| Parameter | Type | Required | Description + +| `feature_identifier` +| string +| Required +| Feature name (`feature_name`) or feature ID (`feature_id`) of the feature to update. + +| `org_identifiers` +| array of integers +| Required +| Numeric IDs of the Orgs to assign. Send an empty array with `operation` set to `REPLACE` to remove all Org assignments for this feature. + +| `operation` +| string +| Optional +| Type of assignment update: `ADD` assigns the given Orgs in addition to existing assignments, `REMOVE` unassigns the given Orgs, or `REPLACE` sets the assignment to exactly the given Orgs. Defaults to `REPLACE`. +|=== + +[CAUTION] +==== +If you omit `operation`, the API uses `REPLACE`. Any Orgs currently assigned to the feature that are not in `org_identifiers` are unassigned. To add Orgs without affecting existing assignments, set `operation` to `ADD`. +==== + +=== Example request: add Org assignments + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/configurations/features/assignments/update' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "feature_identifier": "index_columns", + "org_identifiers": [1, 2], + "operation": "ADD" +}' +---- + +=== API response: add Org assignments + +[source,json] +---- +{ + "feature_id": "feature.search.columnIndexing", + "feature_name": "index_columns", + "assigned_orgs": [ + { "org_id": 1, "org_name": "Acme" }, + { "org_id": 2, "org_name": "Beta" } + ] +} +---- + +=== Example request: remove all Org assignments + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/configurations/features/assignments/update' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "feature_identifier": "index_columns", + "org_identifiers": [], + "operation": "REPLACE" +}' +---- + +== Update feature value + +The `POST /api/rest/2.0/configurations/features/values/update` API endpoint sets the value of a feature at the Cluster or Org scope. Requires the `ADMINISTRATION` or `ORG_ADMINISTRATION` privilege. The `ORG_ADMINISTRATION` privilege applies only to Org admins. + +A successful request returns `200 OK` and a `FeatureValueResponse` object with `feature_id`, `feature_name`, and the updated `feature_value`. + +[WARNING] +==== +Setting `reset_org_overrides` to `true` at `CLUSTER` scope removes all per-Org value overrides for this feature. All Orgs then inherit the new Cluster-level value. This operation cannot be undone through the API. +==== + +=== Request parameters + +[cols="1,1,1,3"] +|=== +| Parameter | Type | Required | Description + +| `scope` +| string +| Required +| Scope at which to set the value: `CLUSTER` or `ORG`. + +| `org_identifier` +| integer +| Conditional +| Numeric ID of the Org for which to set the value. Required when `scope` is `ORG`. Ignored when `scope` is `CLUSTER`. + +| `feature_identifier` +| string +| Required +| Feature name (`feature_name`) or feature ID (`feature_id`) of the feature to update. + +| `feature_value` +| string +| Required +| New value to assign to the feature, as a string. For toggle features, use `"true"` or `"false"`. + +| `reset_org_overrides` +| boolean +| Conditional +| Applicable only when `scope` is `CLUSTER`. When `true`, any existing per-Org value overrides for this feature are also removed so that all Orgs inherit the new Cluster-level value. When `false`, existing per-Org value overrides are retained. Required when `scope` is `CLUSTER` for an Org-aware feature. Must be omitted when `scope` is `ORG`; passing it at `ORG` scope returns a `400` error. +|=== + +=== Example request: set an Org-level override + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/configurations/features/values/update' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "scope": "ORG", + "org_identifier": 1, + "feature_identifier": "index_columns", + "feature_value": "true" +}' +---- + +=== Example request: set Cluster value and reset all Org overrides + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/configurations/features/values/update' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "scope": "CLUSTER", + "feature_identifier": "index_columns", + "feature_value": "true", + "reset_org_overrides": true +}' +---- + +=== API response: set Cluster value and reset all Org overrides + +[source,json] +---- +{ + "feature_id": "feature.search.columnIndexing", + "feature_name": "index_columns", + "feature_value": "true" +} +---- + +== Related resources + +* xref:rest-api-v2-reference.adoc[REST API v2 reference] +* xref:org-manage-api.adoc[Org administration] +* xref:privileges-and-roles.adoc[Privileges and roles] +* xref:roles.adoc[Role-based access control] diff --git a/modules/ROOT/pages/filters_overview.adoc b/modules/ROOT/pages/filters_overview.adoc index fe4672d0d..f618a328f 100644 --- a/modules/ROOT/pages/filters_overview.adoc +++ b/modules/ROOT/pages/filters_overview.adoc @@ -36,7 +36,7 @@ xref:runtime-filters.adoc#_maximum_filter_count[Runtime filter limit] for more i ==== 4. link:https://docs.thoughtspot.com/cloud/latest/liveboard-filters[Liveboard filters, window=_blank] + -Liveboard filters apply to all visualizations on the Liveboard and are visible as UI components at the top of a Liveboard page. When a filter is clicked, a modal with filter options appropriate for the data type is displayed. + +Liveboard filters are visible as UI components at the top of a Liveboard page. #By default, a Liveboard filter applies to all visualizations on the Liveboard. Starting with ThoughtSpot Cloud 26.10.0.cl, a filter can also be scoped to a specific tab or group. For more information, see <>.# When a filter is clicked, a modal with filter options appropriate for the data type is displayed. + Liveboard users can add or modify filters as needed. If you are embedding a Liveboard that includes preset filters, you can programmatically update, reset, or remove filters using `HostEvent.UpdateFilters`. 5. link:https://docs.thoughtspot.com/cloud/latest/liveboard-filters-cross[Liveboard cross filters, window=_blank] + @@ -222,6 +222,37 @@ liveboardEmbed.trigger(HostEvent.UpdateFilters, { }); ---- +[#scoped-filter-updates] +=== #Scoped filter and parameter updates# +#Starting with ThoughtSpot Cloud 26.10.0.cl release, Liveboard filters and parameters can be scoped at three levels:# + +* #*Liveboard*: applies to all visualizations on the Liveboard.# +* #*Tab*: applies only to visualizations on a specific tab.# +* #*Group*: applies only to visualizations in a specific group on a tab.# + +#To enable group-level scoping in an embedded Liveboard, set `isScopedLiveboardFilteringEnabled` to `true` in the embed configuration. For more information, see xref:embed-pinboard.adoc#scoped-liveboard-filtering[Scoped Liveboard filtering].# + +#To scope an update to a tab or group, pass the `applicability` attribute with `HostEvent.UpdateFilters` or `HostEvent.UpdateParameters`. Set `level` to `TAB` or `GROUP`, and set `targetId` to the ID of the tab or group. To get the group IDs on a Liveboard, use `HostEvent.GetGroups`.# + +[source,JavaScript] +---- +const groups = await liveboardEmbed.trigger(HostEvent.GetGroups); + +liveboardEmbed.trigger(HostEvent.UpdateFilters, { + filter: { + column: "Region", + oper: "IN", + values: ["West"], + applicability: { + level: "GROUP", + targetId: groups.orderedGroupIds[0], + }, + }, +}); +---- + +#For more information, see xref:events-hostEvents.adoc#applicability-host-events[Scoped filter and parameter host events].# + === GetFilters and GetParameters events If you want to build your own filter UI within the embedding app, you can find out details of the Liveboard and runtime filters that are defined using `HostEvent.GetFilters`. @@ -238,6 +269,8 @@ Each filter object in the `HostEvent.GetFilters` response includes two additiona * `applicable_viz`: indicates whether the filter applies to `ALL` visualizations or only `SPECIFIC` ones (with a `viz_ids` array). * `linking`: indicates whether the filter is linked to other filters, and which columns it is linked to (`is_linked`, `linked_columns`). +#Starting with Visual Embed SDK 1.53.0, the filter objects returned by `HostEvent.GetFilters` and the parameter objects returned by `HostEvent.GetParameters` also include an optional `applicability` field that indicates whether the filter or parameter is scoped to the Liveboard, a tab, or a group.# + For more information, see xref:events-hostEvents.adoc#_hostevent_getfilters[HostEvent.GetFilters] and xref:HostEvent.adoc#_getfilters[HostEvent reference documentation]. @@ -261,6 +294,8 @@ You can also listen for the user's interactions with the filters using the link: There is an equivalent EmbedEvent for Parameters called link:https://developers.thoughtspot.com/docs/Enumeration_EmbedEvent#_parameterchanged[EmbedEvent.ParameterChanged]. +#Starting with Visual Embed SDK 1.53.0, the `EmbedEvent.FilterChanged` and `EmbedEvent.ParameterChanged` payloads include an optional `applicability` object that describes the scope of the changed filter or parameter. For more information, see xref:event-embedEvents.adoc#applicability-scope[Scoped filter and parameter events].# + === UpdateCrossFilter event You can programmatically trigger an action to update a cross filter using link:https://developers.thoughtspot.com/docs/Enumeration_HostEvent#_updatecrossfilter[HostEvent.UpdateCrossFilter]: diff --git a/modules/ROOT/pages/intro-thoughtspot-objects.adoc b/modules/ROOT/pages/intro-thoughtspot-objects.adoc index e2a2d0b9e..2b9394169 100644 --- a/modules/ROOT/pages/intro-thoughtspot-objects.adoc +++ b/modules/ROOT/pages/intro-thoughtspot-objects.adoc @@ -38,6 +38,8 @@ Currently, `obj_id` is supported for the following object types: * Visualizations * Collections * Personalized Views +* Roles +* Template variables === obj_id format and constraints diff --git a/modules/ROOT/pages/rest-api-csharp-sdk.adoc b/modules/ROOT/pages/rest-api-csharp-sdk.adoc index ce6832f20..30ff3fd77 100644 --- a/modules/ROOT/pages/rest-api-csharp-sdk.adoc +++ b/modules/ROOT/pages/rest-api-csharp-sdk.adoc @@ -323,6 +323,7 @@ await api.ApplyConfigurationAsync(newConfig); [options="header"] |==== |ThoughtSpot release|Recommended SDK version +|ThoughtSpot Cloud: 26.10.0.cl|v2.29.0 or later |ThoughtSpot Cloud: 26.9.0.cl|v2.28.0 or later |ThoughtSpot Cloud 26.8.0.cl|v2.27.1 or later |==== diff --git a/modules/ROOT/pages/rest-api-java-sdk.adoc b/modules/ROOT/pages/rest-api-java-sdk.adoc index 31ef6730b..b9060e5b6 100644 --- a/modules/ROOT/pages/rest-api-java-sdk.adoc +++ b/modules/ROOT/pages/rest-api-java-sdk.adoc @@ -281,6 +281,7 @@ Note the recommendation of Java SDK: [options='header'] |==== |ThoughtSpot release version|Supported SDK version +a|ThoughtSpot Cloud: 26.10.0.cl|v2.29.0 or later |ThoughtSpot Cloud: 26.9.0.cl|v2.28.0 or later |ThoughtSpot Cloud: 26.8.0.cl|v2.27.1 or later |ThoughtSpot Cloud: 26.7.0.cl|v2.26.0 or later diff --git a/modules/ROOT/pages/rest-api-python-sdk.adoc b/modules/ROOT/pages/rest-api-python-sdk.adoc index 6a1cf354b..0e13c5903 100644 --- a/modules/ROOT/pages/rest-api-python-sdk.adoc +++ b/modules/ROOT/pages/rest-api-python-sdk.adoc @@ -373,6 +373,7 @@ on every request. [options='header'] |==== |ThoughtSpot release version|Recommended SDK version +a|ThoughtSpot Cloud: 26.10.0.cl|v2.29.0 or later a|ThoughtSpot Cloud: 26.9.0.cl|v2.28.0 or later a|ThoughtSpot Cloud: 26.8.0.cl | v2.27.1 or later a|ThoughtSpot Cloud: 26.7.0.cl | v2.26.0 or later diff --git a/modules/ROOT/pages/rest-api-sdk-typescript.adoc b/modules/ROOT/pages/rest-api-sdk-typescript.adoc index ddcae33f9..24e8eef4a 100644 --- a/modules/ROOT/pages/rest-api-sdk-typescript.adoc +++ b/modules/ROOT/pages/rest-api-sdk-typescript.adoc @@ -201,6 +201,7 @@ const test = async () => { [options='header'] |==== |ThoughtSpot release version|Recommended SDK version +|ThoughtSpot Cloud: 26.10.0.cl|v2.29.0 or later |ThoughtSpot Cloud: 26.9.0.cl|v2.28.0 or later |ThoughtSpot Cloud: 26.8.0.cl|v2.27.1 or later |ThoughtSpot Cloud: 26.7.0.cl|v2.26.0 or later diff --git a/modules/ROOT/pages/rest-apiv2-changelog.adoc b/modules/ROOT/pages/rest-apiv2-changelog.adoc index 7e201fe2f..91b0afe7c 100644 --- a/modules/ROOT/pages/rest-apiv2-changelog.adoc +++ b/modules/ROOT/pages/rest-apiv2-changelog.adoc @@ -8,6 +8,63 @@ This changelog lists the features and enhancements introduced in REST API v2.0. For information about new features and enhancements available for embedded analytics, see xref:whats-new.adoc[What's New]. +== Version 26.10.0.cl, October 2026 + +=== Spotter AI APIs + +Spotter Analyst APIs:: +ThoughtSpot introduces the following REST API v2.0 endpoints to manage Spotter Analysts programmatically. + +* `POST /api/rest/2.0/ai/agent/analysts/create` + +Creates a Spotter Analyst with a name, description, data sources, and optional instructions, MCP connectors, and starter prompts. +* `POST /api/rest/2.0/ai/agent/analysts/search` + +Returns the Spotter Analysts visible to the caller. +* `POST /api/rest/2.0/ai/agent/analysts/{analyst_identifier}/update` + +Updates a Spotter Analyst. +* `POST /api/rest/2.0/ai/agent/analysts/{analyst_identifier}/delete` + +Deletes a Spotter Analyst. + +For more information, see xref:spotter-analyst-api.adoc[Spotter Analyst API]. + +Pin conversations in the update conversation API:: +The `POST /api/rest/2.0/ai/agent/conversations/{conversation_identifier}/update` endpoint now accepts an `is_pinned` attribute. For more information, see xref:spotter-agent-conversation-mgmt-apis.adoc#update-conversation[Updating a conversation]. + +Spotter conversation enhancements:: + +* The `POST /api/rest/2.0/ai/agent/conversation/create` endpoint accepts an optional `analyst_identifier` to start the conversation from a Spotter Analyst, using the Analyst's data sources, instructions, and connectors. `metadata_context` is now required only when `analyst_identifier` is not provided; passing both or neither is rejected. The response includes the Analyst's `analyst_id` when applicable, and the `GET /api/rest/2.0/ai/agent/conversations` list response includes `analyst_id` per conversation. +* The `POST /api/rest/2.0/ai/agent/conversations/{conversation_identifier}/share` endpoint accepts an optional `notify_on_share` boolean. When `true` (default), recipients receive an in-app notification. + +=== TML and metadata type additions + +* The `TEMPLATE_VARIABLE` type is supported on `POST /api/rest/2.0/metadata/tml/export`, `POST /api/rest/2.0/metadata/update-obj-id`, and `POST /api/rest/2.0/metadata/headers/update`. +* The `ROLE` type is supported on `POST /api/rest/2.0/metadata/update-obj-id` and `POST /api/rest/2.0/metadata/headers/update`. The `POST /api/rest/2.0/template/variables/create` and `search` endpoints return `obj_id` in the response. + +=== Databricks semantic integrations + +The `POST /api/rest/2.0/semantic-integrations/create` endpoint accepts the `RDBMS_DATABRICKS` integration type, and the `search` endpoint returns it. + +=== Feature Management API +This release introduces the following new REST API v2.0 endpoints for programmatic feature management. + +* `POST /api/rest/2.0/configurations/features/search` + +Returns feature configurations grouped by feature group. +* `POST /api/rest/2.0/configurations/features/assignments/update` + +Updates Org assignments for a feature using `ADD`, `REMOVE`, or `REPLACE` operations. +* `POST /api/rest/2.0/configurations/features/values/update` + +Sets feature value at `CLUSTER` or `ORG` scope. + +For more information, see xref:feature-management-api.adoc[Feature Management API]. + +=== Multi-Org tokens [beta betaBackground]^Beta^ + +Authentication token endpoints now support Org scope at issuance and inspection: + +* The `/api/rest/2.0/auth/token/full`, `/api/rest/2.0/auth/token/custom`, and `/api/rest/2.0/auth/token/object` endpoints accept an optional `scope` object to allow administrators to generate multi-org tokens. +* Token responses, including `POST /api/rest/2.0/auth/token/validate`, retrun `scope/org_scope` and `scope/org_ids`, indicating the Orgs the token is authorized for. +* API requests made with a multi-Org token select the target Org using the `X-Org-Selector` header. The header selects from the Orgs already authorized on the token; it does not grant new access. + +For more information, see xref:authentication.adoc#multi-org-tokens[Multi-Org tokens]. + == Version 26.9.0.cl, September 2026 === Answer Export API diff --git a/modules/ROOT/pages/semantic-integrations-api.adoc b/modules/ROOT/pages/semantic-integrations-api.adoc index 0a9f80a9e..9a232d075 100644 --- a/modules/ROOT/pages/semantic-integrations-api.adoc +++ b/modules/ROOT/pages/semantic-integrations-api.adoc @@ -18,12 +18,6 @@ You can use the semantic integration APIs to automate the following tasks: * Re-import a semantic integration to refresh the ThoughtSpot model after the source Snowflake Semantic View has changed. * Delete a semantic integration and its generated ThoughtSpot model. -[NOTE] -==== -The semantic integration APIs are available on ThoughtSpot Cloud instances from 26.9.0.cl. -Snowflake is the only supported CDW connector type (`RDBMS_SNOWFLAKE`). -==== - == Prerequisites To use these APIs, the authenticated user must have one of the following privileges: @@ -52,31 +46,35 @@ To create a new semantic integration by reading the specified Snowflake Semantic === Request parameters -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Parameter | Type | Required | Description -| `connection_identifier` | String | Yes | GUID or name of the Snowflake connection in ThoughtSpot. -| `name` | String | Yes | Display name for the semantic integration. Must be unique. -| `database_name` | String | Yes | Database name in the Snowflake CDW that contains the semantic view. -| `schema_name` | String | Yes | Schema name in the Snowflake CDW that contains the semantic view. -| `semantic_view_name` | String | Yes | Name of the Snowflake Semantic View to integrate. -| `type` | String | Yes | CDW connector type. Only accepted value: `RDBMS_SNOWFLAKE`. -| `description` | String | No | Optional description for the semantic integration. -| `tags` | Array | No | Tag GUIDs or names to associate with the integration. +| Parameter | Description +|`connection_identifier` |__String__. GUID or name of the Snowflake connection in ThoughtSpot. +|`name` |__String__. Display name for the semantic integration. Must be unique. +|`database_name` |__String__. Database name in the Snowflake CDW that contains the semantic view. +|`schema_name` |__String__. Schema name in the Snowflake CDW that contains the semantic view. +|`semantic_view_name` |__String__. Name of the Snowflake Semantic View to integrate. +|`type` a|__String__. CDW connector type. Valid values: + +* `RDBMS_SNOWFLAKE` +* `RDBMS_DATABRICKS` + +|`description` |__String__. Optional. Description of the semantic integration. +|`tags` |__Array__. Optional. Tag GUIDs or names to associate with the integration. |===== === Response fields -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Field | Type | Description -| `id` | String | GUID of the newly created semantic integration. -| `name` | String | Display name of the semantic integration. -| `model_id` | String | GUID of the ThoughtSpot data model generated for this integration. -| `model_name` | String | Display name of the generated ThoughtSpot data model. -| `semantic_report` | Object | Per-formula import report. See <<_semantic_report_fields>>. +| Field | Description +|`id` |__String__. GUID of the newly created semantic integration. +|`name` |__String__. Display name of the semantic integration. +|`model_id` |__String__. GUID of the ThoughtSpot data model generated for this integration. +|`model_name` |__String__. Display name of the generated ThoughtSpot data model. +|`semantic_report` |__Object__. Per-formula import report. See <<_semantic_report_fields>>. |===== [#semantic-report-fields] @@ -86,29 +84,29 @@ The `semantic_report` object contains a summary and a list of per-formula import `summary` fields: -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Field | Type | Description -| `total` | Integer | Total number of formulas in the Snowflake Semantic View. -| `imported` | Integer | Number of formulas successfully imported. -| `failed` | Integer | Number of formulas that failed to import. -| `skipped` | Integer | Number of formulas that were skipped. +| Field | Description +|`total` |__Integer__. Total number of formulas in the Snowflake Semantic View. +|`imported` |__Integer__. Number of formulas successfully imported. +|`failed` |__Integer__. Number of formulas that failed to import. +|`skipped` |__Integer__. Number of formulas that were skipped. |===== `formulas` array — each entry contains: -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Field | Type | Description -| `id` | String | Formula GUID in the generated ThoughtSpot model. -| `name` | String | Formula name. -| `description` | String | Formula description. -| `source_expression` | String | Original CDW expression. -| `translated_formula` | String | Equivalent ThoughtSpot formula expression. -| `import_status` | String | One of `IMPORTED`, `FAILED`, or `SKIPPED`. -| `change_status` | String | One of `NEW`, `UPDATED`, or `UNCHANGED`. Null on initial create (populated by import). +| Field | Description +|`id` |__String__. Formula GUID in the generated ThoughtSpot model. +|`name` |__String__. Formula name. +|`description` |__String__. Formula description. +|`source_expression` |__String__. Original CDW expression. +|`translated_formula` |__String__. Equivalent ThoughtSpot formula expression. +|`import_status` |__String__. One of `IMPORTED`, `FAILED`, or `SKIPPED`. +|`change_status` |__String__. One of `NEW`, `UPDATED`, or `UNCHANGED`. Null on initial create (populated by import). |===== === Example request @@ -169,51 +167,51 @@ To fetch a paginated list of semantic integrations matching the specified criter === Request parameters -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Parameter | Type | Required | Description -| `pattern` | String | No | Substring filter to narrow search results by integration name. -| `author_identifiers` | Array | No | Filter by the GUID or username of the user who created the integration. -| `connection_identifiers` | Array | No | Filter by the GUID or name of the Snowflake connection associated with the integration. -| `sort_options` | Object | No | Sort configuration. See <<_sort_options>>. -| `record_offset` | Integer | No | Number of records to skip for pagination. Minimum: 0. Default: 0. -| `record_size` | Integer | No | Maximum number of records to return. Use `0` to return all records. Default: 10. +| Parameter | Description +|`pattern` |__String__. Optional. Substring filter to narrow search results by integration name. +|`author_identifiers` |__Array__. Optional. Filter by the GUID or username of the user who created the integration. +|`connection_identifiers` |__Array__. Optional. Filter by the GUID or name of the Snowflake connection associated with the integration. +|`sort_options` |__Object__. Optional. Sort configuration. See <<_sort_options>>. +|`record_offset` |__Integer__. Optional. Number of records to skip for pagination. Minimum: 0. Default: 0. +|`record_size` |__Integer__. Optional. Maximum number of records to return. Use `0` to return all records. Default: 10. |===== [#sort-options] ==== Sort options -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Field | Type | Description -| `field_name` | String | Sort field. One of: `NAME`, `AUTHOR`, `CREATED_TIME`, `MODIFIED_TIME`. -| `order` | String | Sort direction. `ASC` for ascending, `DESC` for descending. +| Field | Description +|`field_name` |__String__. Sort field. One of: `NAME`, `AUTHOR`, `CREATED_TIME`, `MODIFIED_TIME`. +|`order` |__String__. Sort direction. `ASC` for ascending, `DESC` for descending. |===== === Response fields Returns an array of objects, each with the following fields: -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Field | Type | Description -| `id` | String | GUID of the semantic integration. -| `name` | String | Display name of the semantic integration. -| `description` | String | Description of the semantic integration. Null if not set. -| `model_id` | String | GUID of the associated ThoughtSpot data model. -| `model_name` | String | Display name of the associated ThoughtSpot data model. -| `import_type` | String | How the semantic definition was sourced. `CDW` for Snowflake Semantic View; `FILE` for file upload. -| `type` | String | CDW connector type. Currently always `RDBMS_SNOWFLAKE`. -| `connection_id` | String | GUID of the Snowflake connection. -| `connection_name` | String | Display name of the Snowflake connection. -| `author_id` | String | GUID of the user who created the integration. -| `author_name` | String | Username of the user who created the integration. -| `creation_time_in_millis` | Float | Creation time in Unix epoch milliseconds. -| `modification_time_in_millis` | Float | Last modification time in Unix epoch milliseconds. -| `tags` | Array | Tags associated with the integration, each with `id` and `name`. +| Field | Description +|`id` |__String__. GUID of the semantic integration. +|`name` |__String__. Display name of the semantic integration. +|`description` |__String__. Description of the semantic integration. Null if not set. +|`model_id` |__String__. GUID of the associated ThoughtSpot data model. +|`model_name` |__String__. Display name of the associated ThoughtSpot data model. +|`import_type` |__String__. How the semantic definition was sourced. `CDW` for Snowflake Semantic View; `FILE` for file upload. +|`type` |__String__. CDW connector type. Either `RDBMS_SNOWFLAKE` or `RDBMS_DATABRICKS`. +|`connection_id` |__String__. GUID of the Snowflake connection. +|`connection_name` |__String__. Display name of the Snowflake connection. +|`author_id` |__String__. GUID of the user who created the integration. +|`author_name` |__String__. Username of the user who created the integration. +|`creation_time_in_millis` |__Float__. Creation time in Unix epoch milliseconds. +|`modification_time_in_millis` |__Float__. Last modification time in Unix epoch milliseconds. +|`tags` |__Array__. Tags associated with the integration, each with `id` and `name`. |===== === Example request @@ -253,11 +251,11 @@ The import operation: === Path parameters -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Parameter | Type | Required | Description -| `semantic_integration_identifier` | String | Yes | GUID or name of the semantic integration to re-import. +| Parameter | Description +|`semantic_integration_identifier` |__String__. Path parameter. GUID or name of the semantic integration to re-import. |===== === Response fields @@ -336,11 +334,11 @@ Deletion is permanent and cannot be undone. If you need to restore the integrati === Path parameters -[width="100%"] +[width="100%" cols="2,4"] [options="header"] |===== -| Parameter | Type | Required | Description -| `semantic_integration_identifier` | String | Yes | GUID or name of the semantic integration to delete. +| Parameter | Description +|`semantic_integration_identifier` |__String__. Path parameter. GUID or name of the semantic integration to delete. |===== === Example request diff --git a/modules/ROOT/pages/spotter-agent-conversation-apis.adoc b/modules/ROOT/pages/spotter-agent-conversation-apis.adoc index 1e094a6aa..4aa924ef6 100644 --- a/modules/ROOT/pages/spotter-agent-conversation-apis.adoc +++ b/modules/ROOT/pages/spotter-agent-conversation-apis.adoc @@ -15,7 +15,14 @@ For information about receiving responses as a real-time event stream, see xref: The `/api/rest/2.0/ai/agent/conversation/create` API endpoint creates a new conversation session with Spotter Agent for a specific or multi-data context and returns a conversation ID. === Request parameters -The request body must include the `metadata_context`. REST API clients must have at least view access to the data source objects specified in the API request to create a conversation session and use it for subsequent queries. +The request body must include the conversation context with exactly one of the following parameters: + +* `metadata_context` to set the data context directly. +* `analyst_identifier` to start the conversation from a Spotter Analyst. + +Passing both, or neither, is rejected with a `422` error. + +REST API clients must have at least view access to the data source objects specified in the API request to create a conversation session and use it for subsequent queries. [width="100%" cols="2,4"] [options='header'] @@ -33,6 +40,8 @@ To set multi-data context, use `data_source_identifiers`. ** `data_source` [.version-badge.deprecated]#Deprecated# + This option is deprecated in 26.5.0.cl. ThoughtSpot recommends using the `DATA_SOURCE` with `data_source_context` and data source IDs instead. +|`analyst_identifier` |__String__. Optional. Unique identifier of a Spotter Analyst to start the conversation from. The conversation uses the Analyst's configuration, including its data sources, agent instructions, and connectors, so `metadata_context` must be omitted. For information about Analyst management endpoints, see xref:spotter-analyst-api.adoc[Spotter Analyst API]. + |`conversation_settings` a|__Optional__. Defines additional parameters for the conversation context. You can set any of the following attributes as needed: * `enable_contextual_change_analysis` + @@ -86,6 +95,23 @@ curl -X POST \ }' ---- +Start a conversation from a Spotter Analyst:: + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/ai/agent/conversation/create' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {AUTH_TOKEN}' \ + --data-raw '{ + "analyst_identifier": "{analyst-guid}", + "conversation_settings": { + "enable_save_chat": true + } +}' +---- + For multi-data source context:: [source,cURL] @@ -119,7 +145,8 @@ If the API request is successful, the API returns the conversation ID and identi ---- { "conversation_id": "wwHQ5j8O8dQC", - "conversation_identifier": "wwHQ5j8O8dQC" + "conversation_identifier": "wwHQ5j8O8dQC", + "analyst_id": "9f8e7d6c-5b4a-3210-fedc-ba9876543210" } ---- @@ -127,6 +154,8 @@ If the API request is successful, the API returns the conversation ID and identi Use this for all subsequent message calls. * `conversation_id` [.version-badge.deprecated]#Deprecated# + Returns the same value as `conversation_identifier`. +* `analyst_id` + +If the conversation context uses a Spotter Analyst agent, the API endpoint returns the `analyst_id` in response. The value is `null` otherwise. == Send queries to a conversation session diff --git a/modules/ROOT/pages/spotter-agent-conversation-mgmt-apis.adoc b/modules/ROOT/pages/spotter-agent-conversation-mgmt-apis.adoc index a4bc98671..1d83c24c1 100644 --- a/modules/ROOT/pages/spotter-agent-conversation-mgmt-apis.adoc +++ b/modules/ROOT/pages/spotter-agent-conversation-mgmt-apis.adoc @@ -33,8 +33,8 @@ Use this endpoint to resolve `answer_id` references returned by the get conversa __Available on ThoughtSpot Cloud instances from 26.7.0.cl onwards.__ a|`POST /api/rest/2.0/ai/agent/conversations/{conversation_identifier}/update` + -xref:spotter-agent-conversation-mgmt-apis.adoc#update-conversation[Updates the metadata of a saved conversation], such as renaming its title. + -__Available on ThoughtSpot Cloud instances from 26.7.0.cl onwards.__ +xref:spotter-agent-conversation-mgmt-apis.adoc#update-conversation[Updates the metadata of a saved conversation], such as renaming its title or pinning it to the top of the conversation list. + +__Available on ThoughtSpot Cloud instances from 26.7.0.cl onwards. The `is_pinned` attribute is available from 26.10.0.cl onwards.__ a|`DELETE /api/rest/2.0/ai/agent/conversations/{conversation_identifier}/delete` + xref:spotter-agent-conversation-mgmt-apis.adoc#delete-conversation[Deletes a saved conversation] and all its messages. + @@ -63,6 +63,7 @@ curl -X POST \ }' ---- +=== API response If the API request is successful, ThoughtSpot returns the conversation IDs. [source,JSON] @@ -311,6 +312,7 @@ Each item in `conversations` represents a saved conversation. |`updated_at`|__String__. Timestamp of when the conversation was last updated. |`data_source_identifiers` a|__Array of strings__. Unique identifiers of the data sources associated with the conversation. |`data_source_names` a|`DataSourceEntry[]`. Display names and identifiers for the data sources associated with the conversation. +|`analyst_id`|__String__. Unique identifier of the Spotter Analyst the conversation was started from. The value is `null` for conversations not started from an Analyst. |===== ==== DataSourceEntry @@ -444,7 +446,12 @@ If the API request is successful, ThoughtSpot returns a response body with the a [#update-conversation] == Update a conversation -To update the metadata of an existing conversation, send a `POST` request to the `/api/rest/2.0/ai/agent/conversations/{conversation_identifier}/update` API endpoint with the conversation ID in the request URL. Currently, the API endpoint allows you to rename the conversation title only. +To update the metadata of an existing conversation, send a `POST` request to the `/api/rest/2.0/ai/agent/conversations/{conversation_identifier}/update` API endpoint with the conversation ID in the request URL. The API endpoint allows you to rename the conversation title and pin or unpin the conversation. + +[NOTE] +==== +Only conversations created with `enable_save_chat: true` can be pinned. Unsaved conversations are not persisted and cannot be retrieved. +==== === Request parameters @@ -454,6 +461,8 @@ To update the metadata of an existing conversation, send a `POST` request to the |Parameter|Description |`conversation_identifier`|__String__. Path parameter. Unique identifier of the conversation to update. |`title`|__String__. Form parameter to include in the request body. To rename the display title of the conversation, specify the title string. +|`is_pinned`|__Boolean__. When set to `true`, it pins the conversation for the user. Pinned conversations are surfaced first in `getConversationList`. +Set to `true` to pin the conversation, `false` to unpin a chat, or omit to leave the pinned state unchanged. Only conversations created with `enable_save_chat: true` can be pinned. |===== ==== API request example @@ -465,10 +474,38 @@ curl -X POST \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer {AUTH_TOKEN}' \ --data-raw '{ + "is_pinned": true, "title": "Revenue Analysis — Q1 2026" }' ---- +==== API request example: pin a conversation + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/ai/agent/conversations/0iwTDJU-tlkm/update' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {AUTH_TOKEN}' \ + --data-raw '{ + "is_pinned": true +}' +---- + +==== API request example: update title and pin state in a single request + +[source,cURL] +---- +curl -X POST \ + --url 'https://{ThoughtSpot-Host}/api/rest/2.0/ai/agent/conversations/0iwTDJU-tlkm/update' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {AUTH_TOKEN}' \ + --data-raw '{ + "title": "Revenue Analysis — Q1 2026", + "is_pinned": true +}' +---- + === API response A successful request returns the 204 response. diff --git a/modules/ROOT/pages/spotter-agent-sharing-apis.adoc b/modules/ROOT/pages/spotter-agent-sharing-apis.adoc index 961315f26..caaac29e4 100644 --- a/modules/ROOT/pages/spotter-agent-sharing-apis.adoc +++ b/modules/ROOT/pages/spotter-agent-sharing-apis.adoc @@ -58,7 +58,7 @@ Do not include the same principal identifiers in both `grant` and `revoke` array | `grant` |__Array of strings__. Array of principals to grant access to the conversation specified in the request. Specify `principal_identifier` and `principal_type`. Specify the principal type, name or GUID of the intended recipients. All recipients are granted a `READ_ONLY` access. | `revoke` |__Array of strings__. Principals to revoke access from. Specify `principal_identifier` and `principal_type`. Specify the principal type, name or GUID of the recipients to revoke access from. | `refresh_shared_content` |__Boolean__. When set to `true`, ThoughtSpot regenerates the shared view from the latest conversation state, even if a shared view already exists. When `false`, reuses the existing shared view. Default is `false`. -//| `notify_on_share` |__Boolean__. When set to `true`, ThoughtSpot sends an in-app notification to the recipients of the shared content. Default is `true`. Available from 26.10.0.cl. +| `notify_on_share` |__Boolean__. When set to `true`, ThoughtSpot sends an in-app notification to the recipients of the shared content. Default is `true`. |===== === Request examples diff --git a/modules/ROOT/pages/spotter-analyst-api.adoc b/modules/ROOT/pages/spotter-analyst-api.adoc new file mode 100644 index 000000000..a578213ab --- /dev/null +++ b/modules/ROOT/pages/spotter-analyst-api.adoc @@ -0,0 +1,500 @@ += Spotter Analyst API +:toc: true +:toclevels: 2 +:page-title: Spotter Analyst API +:page-pageid: spotter-analyst-api +:page-description: Create, search, update, and delete Spotter Analysts using the REST API + +ThoughtSpot Spotter Analysts are governed AI agents, each configured with a name, description, one or more data sources, and optional instructions, Model Context Protocol (MCP) connectors, and starter prompts. Users converse with an Analyst directly in the Spotter interface. + +== Supported endpoints + +Use the following endpoints to create, search, update, share, or delete Analysts programmatically: + +[width="100%", cols="1"] +|===== +a|`POST /api/rest/2.0/ai/agent/analysts/create` + +xref:spotter-analyst-api.adoc#create-analyst[Creates a Spotter Analyst] with a name, description, data sources, and optional instructions, MCP connectors, and starter prompts. + +__Available on ThoughtSpot Cloud instances from 26.10.0.cl onwards.__ + +a|`POST /api/rest/2.0/ai/agent/analysts/search` + +xref:spotter-analyst-api.adoc#search-analysts[Retrieves Analysts visible to the caller], either a single Analyst by identifier or a paginated list ordered by most recent access. + +__Available on ThoughtSpot Cloud instances from 26.10.0.cl onwards.__ + +a|`POST /api/rest/2.0/ai/agent/analysts/{analyst_identifier}/update` + +xref:spotter-analyst-api.adoc#update-analyst[Updates a Spotter Analyst]. The update is a full replace; omitted optional fields are cleared. + +__Available on ThoughtSpot Cloud instances from 26.10.0.cl onwards.__ + +a|`POST /api/rest/2.0/ai/agent/analysts/{analyst_identifier}/share` [beta betaBackground]^Beta^ + +xref:spotter-analyst-api.adoc#share-analyst[Updates share permissions on a Spotter Analyst] for one or more users or groups. Granting access also shares the Analyst's data sources with the principal. + +__Available on ThoughtSpot Cloud instances from 26.10.0.cl onwards.__ + +a|`POST /api/rest/2.0/ai/agent/analysts/{analyst_identifier}/delete` + +xref:spotter-analyst-api.adoc#delete-analyst[Permanently deletes a Spotter Analyst]. This operation is irreversible. + +__Available on ThoughtSpot Cloud instances from 26.10.0.cl onwards.__ +|===== + +== Analyst object + +Each AI Analyst object in ThoughtSpot has the following properties: + +* `id` + +__String__. Server-assigned unique identifier. + +* `name` + +__String__. Display name of the Analyst. + +* `description` + +__String__. Description of the Analyst. Maximum 200 characters. + +* `instructions` + +__String__. Optional natural-language behavior guidelines for the agent. + +* `sources` + +__Array of strings__. Data sources the Analyst can query. Each source includes an `id`, `type`, and display `name`. Supported types: `MODEL`, `ANSWER`, `LIVEBOARD`, `CONVERSATION`. + +* `mcp_connectors` + +__Array of strings__. Linked MCP connectors. Each connector includes `id`, `name`, and `icon_url`. + +* `starter_prompts` + +__Array of strings__. Up to 4 suggested prompts shown on the Analyst landing page. Each entry includes `label`, `text`, `order`, and `is_ai_generated`. + +* `icon_id` + +__String__. Analyst icon identifier. Analysts created via the API use the default icon until one is set in the UI. + +* `updated_time_in_millis` + +__Integer__. Epoch timestamp in milliseconds of the last update. + +* `last_accessed_time_in_millis` + +__Integer__. Epoch timestamp in milliseconds of the last access. + +* `created_by` + +User who created the Analyst. Includes `id`, `name`, and `display_name`. + +* `updated_by` + +User who last updated the Analyst. Includes `id`, `name`, and `display_name`. + + +[#create-analyst] +== Create an analyst +To create a Spotter Analyst programmatically, send a `POST` request to the `/api/rest/2.0/ai/agent/analysts/create` endpoint with the Analyst definition in the request body. The definition includes a name, a description, and at least one data source, and can optionally include instructions, MCP connectors, and starter prompts. + +Use this endpoint to provision governed Analysts as part of an automated deployment workflow, or to create Analysts programmatically across environments. + +[NOTE] +==== +Analysts created via the API use the default icon until one is set in the ThoughtSpot UI. +==== + +=== Required privileges + +Requires at least one of the following privileges: + +* `ADMINISTRATION` +* `CAN_MANAGE_SPOTTER` +* `CAN_USE_SPOTTER` + +The user must also have at least view access to the data sources specified in the API request. + +=== Request parameters + +[width="100%" cols="2,4"] +[options="header"] +|===== +| Parameter | Description +| `name` |__String__. Display name of the Analyst. +| `description` |__String__. Description of the Analyst. Maximum 200 characters. +| `sources` a|__Array of objects__. Data sources the Analyst can query. At least one source is required. The caller must have view access to every referenced source. For each source object, specify the following attributes: + +* `identifier` + +__String__. Unique ID of the data source object. +* `type` + +__String__. Type of the data source object. Valid values: `MODEL`, `ANSWER`, `LIVEBOARD`, and `CONVERSATION`. +* `name` + +__String__. Optional. Display name of the data source. +| `instructions` |__String__. Optional. Natural-language instructions that guide the agent's behavior. Instructions that conflict with system guardrails are rejected with a `409` error. +| `mcp_connector_identifiers` |__Array of strings__. Optional. Identifiers of MCP connectors to link to the Analyst. +| `starter_prompts` |__Array of strings__. Optional. Up to 4 plain-text prompts, each between 10 and 250 characters. Display order follows list position. +|===== + +=== Request example + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/ai/agent/analysts/create' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "name": "Revenue Analyst", + "description": "Answers revenue questions using the Sales data model.", + "sources": [ + { + "identifier": "{model-guid}", + "type": "MODEL" + } + ], + "instructions": "Focus on year-over-year comparisons. Do not surface raw transaction data.", + "starter_prompts": [ + "What was total revenue last quarter?", + "Compare revenue by region for the past 12 months." + ] +}' +---- + +=== API Response + +Returns `200 OK` and the created `Analyst` object, including the server-assigned `id`. + + +//// +=== Error responses + +[cols="1,3"] +|=== +| HTTP status code | Description + +| 400 | Malformed request. +| 401 | Bearer token is missing, expired, or invalid. +| 403 | Insufficient privileges, or the caller does not have view access to a referenced data source. +| 409 | The `instructions` value conflicts with system guardrails. +| 422 | Validation failure: a required field is missing, `sources` is empty, the starter prompt count exceeds 4, or a field-length limit is violated. +| 429 | Rate limit exceeded. +| 500 | Unexpected server error. +|=== +//// + + +[#search-analysts] +== Search analysts +To retrieve the Spotter Analysts visible to the authenticated user, send a `POST` request to the `/api/rest/2.0/ai/agent/analysts/search` endpoint. Use this endpoint to fetch a specific Analyst by its identifier, or to render an Analyst catalog or picker in your app. + +This endpoint operates in two modes: + +Fetch mode:: Provide `analyst_identifier` in the request body to retrieve a single Analyst. All other filters are ignored and `total_size` is `1`. +List mode:: Omit `analyst_identifier` to get a paginated list of Analysts, ordered by most recently accessed. + +=== Required privileges +Requires at least one of the following privileges: + +* `ADMINISTRATION` +* `CAN_MANAGE_SPOTTER` +* `CAN_USE_SPOTTER` + +=== Request parameters + +[width="100%" cols="2,4"] +[options="header"] +|===== +| Parameter | Description +| `analyst_identifier` |__String__. Optional. When provided, returns exactly this Analyst. All other filters are ignored. +| `record_size` |__Integer__. Optional. Number of records per page. The default value is `50`. The supported range is 1 to 500. +| `record_offset` |__Integer__. Optional. Zero-based index of the first record. The default value is `0`. The maximum value is `10000`. +| `query` |__String__. Optional. Case-insensitive substring match on Analyst name. +| `type` |__String__. Optional. Ownership filter. Valid values are `ALL` (default, returns Analysts created by or shared with the caller), `CREATED_BY_ME`, and `SHARED_TO_ME`. +|===== + + +=== Request examples + +List all Analysts:: + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/ai/agent/analysts/search' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "record_size": 50, + "record_offset": 0, + "type": "ALL" +}' +---- + +Fetch a single Analyst:: + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/ai/agent/analysts/search' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "analyst_identifier": "{analyst-guid}" +}' +---- + +=== API Response + +Returns `200 OK` and an `AnalystSearchResponse` object with: + +* `analysts`: the current page of matching `Analyst` objects. +* `total_size`: total count of matching Analysts before pagination. + +//// +=== Error responses + +[cols="1,3"] +|=== +| HTTP status code | Description + +| 403 | Missing privileges, or (fetch mode) the caller does not have access to the requested Analyst. +| 404 | (Fetch mode) No Analyst with the given identifier exists in the caller's Org. +| 422 | `record_size` or `record_offset` is out of the permitted range. +|=== +//// + + +[#update-analyst] +== Update an analyst +To modify an existing Spotter Analyst, send a `POST` request to the `/api/rest/2.0/ai/agent/analysts/{analyst_identifier}/update` endpoint. The Analyst to update is identified by the `analyst_identifier` URL path parameter, and the new definition is passed in the request body. + +The update is a full replace: the Analyst is rewritten from the request body, and any optional field omitted from the request is cleared. Include all fields you want to retain. + +When new sources are added, they are automatically shared with users the Analyst was previously shared with. Those users retain access to a working Analyst. + + +=== Required privileges +Requires at least one of the following privileges: + +* `ADMINISTRATION` +* `CAN_MANAGE_SPOTTER` + +The API endpoint doesn't allow users to edit the Analyst objects that are shared with them by another user. + +=== Request parameters + +[width="100%" cols="2,2,4"] +[options="header"] +|===== +| Parameter | Type | Description +| `analyst_identifier` | Path parameter |__String__. Unique identifier of the Analyst to update, as returned by the Create an analyst or Search analysts endpoint. +| `name` | Form parameter |__String__. Display name of the Analyst. +| `description` | Form parameter |__String__. Description of the Analyst. Maximum 200 characters. +| `sources` | Form parameter |__Array of objects__. Data sources the Analyst can query. Replaces the existing list in full. When new sources are added, they are automatically shared with users the Analyst was previously shared with, so those users keep a working Analyst. +| `instructions` | Form parameter |__String__. Optional. Natural-language instructions that guide the agent's behavior. Instructions that conflict with system guardrails are rejected with a `409` error. If instructions are not specified, any existing instructions on the Analyst are removed. +| `mcp_connector_identifiers` | Form parameter |__Array of strings__. Optional. Identifiers of MCP connectors to link to the Analyst. Replaces the existing list in full. To remove the existing connectors, pass an empty array. +| `starter_prompts` | Form parameter |__Array of strings__. Optional. Up to 4 plain-text prompts, each between 10 and 250 characters. Replaces the existing list in full. To remove the existing starter prompts, pass an empty array. +|===== + + +=== Request examples + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/ai/agent/analysts/{analyst_identifier}/update' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "name": "Revenue Analyst v2", + "description": "Updated to include APAC data model.", + "sources": [ + { + "identifier": "{model-guid}", + "type": "MODEL" + }, + { + "identifier": "{apac-model-guid}", + "type": "MODEL" + } + ], + "starter_prompts": [ + "What was total revenue last quarter?", + "Compare revenue by region for the past 12 months.", + "Show top 10 products by APAC revenue." + ] +}' +---- + +[NOTE] +==== +The update operation replaces existing properties of the Analyst object. Ensure that you include every parameter that you want to keep. +==== + + +=== API Response +Returns `200 OK` and the updated `Analyst` object, including the refreshed `updated_time_in_millis` and `updated_by` fields. + +//// +=== Error responses + +[cols="1,3"] +|=== +| HTTP status code | Description + +| 400 | Malformed `analyst_identifier`. +| 401 | Bearer token is missing, expired, or invalid. +| 403 | The caller is not the Analyst owner and does not hold admin or Spotter-management privileges. +| 404 | No Analyst with the given identifier exists in the caller's Org. +| 409 | The `instructions` value conflicts with system guardrails. +| 422 | Validation failure: a required field is missing, `sources` is empty, the starter prompt count exceeds 4, or a field-length limit is violated. +| 429 | Rate limit exceeded. +| 500 | Unexpected server error. +|=== +//// + +[#share-analyst] +== Share an analyst [beta betaBackground]^Beta^ +To share a Spotter Analyst with other ThoughtSpot users and groups, or to change or revoke their access, send a `POST` request to the `/api/rest/2.0/ai/agent/analysts/{analyst_identifier}/share` endpoint. The Analyst to share is identified by the `analyst_identifier` URL path parameter, and the permission assignments are passed in the request body, one entry per principal. + +Use `READ_ONLY` or `MODIFY` to grant or change a principal's access, and `NO_ACCESS` to revoke it. When access is granted, the Analyst's data sources are automatically shared with the principal, so the Analyst keeps working for them. + +Users the Analyst is shared with can use it but cannot edit it. To allow editing, set `share_mode` to `MODIFY`. + +=== Required privileges +Requires at least one of the following privileges: + +* `ADMINISTRATION` +* `CAN_MANAGE_SPOTTER` + +Use a Bearer token for the Org in which the Analyst exists. + +=== Request parameters + +Specify the `analyst_identifier` as a path parameter. + +The request body contains a `permissions` array with one entry per principal. A principal may appear at most once per request. + +[width="100%" cols="2,2,4"] +[options="header"] +|==== +| Parameter |Type |Description +| `analyst_identifier` |Path parameter |__String__. Unique identifier of the Analyst to share, as returned by the Create an analyst or Search analysts endpoint. +| `permissions` a|Form parameter a|__Array of objects__. Permission assignments, one entry per principal. A principal may appear at most once per request. For each entry, specify the following attributes: + +* `principal` + +__Object__. The user or group to assign access to. Specify the following attributes: + +** `identifier` + +__String__. Unique identifier of the user or group. +** `type` + +__String__. Type of principal. Valid values: `USER` and `USER_GROUP`. + +* `share_mode` + +__String__. Access level to assign. `READ_ONLY` or `MODIFY` grants or changes the principal's access. `NO_ACCESS` revokes it. +|==== + + +=== Request examples + +Share with a user and a group:: + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/ai/agent/analysts/{analyst_identifier}/share' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "permissions": [ + { + "principal": { + "identifier": "{user-guid}", + "type": "USER" + }, + "share_mode": "READ_ONLY" + }, + { + "principal": { + "identifier": "{group-guid}", + "type": "USER_GROUP" + }, + "share_mode": "MODIFY" + } + ] +}' +---- + +Revoke access:: + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/ai/agent/analysts/{analyst_identifier}/share' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer {token}' \ + --data-raw '{ + "permissions": [ + { + "principal": { + "identifier": "{user-guid}", + "type": "USER" + }, + "share_mode": "NO_ACCESS" + } + ] +}' +---- + + +=== API Response + +Returns an empty `204 No Content` response on success. + + +//// +=== Error responses + +[cols="1,3"] +|=== +| HTTP status code | Description + +| 400 | Malformed `analyst_identifier`. +| 401 | Bearer token is missing, expired, or invalid. +| 403 | The caller is not the Analyst owner and does not hold admin or Spotter-management privileges. +| 404 | No Analyst with the given identifier exists in the caller's Org. +| 422 | Validation failure: empty `permissions` array, duplicate principal, or a missing required field. +| 429 | Rate limit exceeded. +| 500 | Unexpected server error. +|=== +//// + +[#delete-analyst] +== Delete an analyst +To permanently delete a Spotter Analyst, send a `POST` request to the `/api/rest/2.0/ai/agent/analysts/{analyst_identifier}/delete` endpoint with the Analyst's unique identifier as the URL path parameter. No request body is required. + +[WARNING] +==== +This operation is irreversible. Deleted Analysts cannot be recovered. +==== + +=== Required privileges +The owners of the Analyst object specified in the API request can delete the object. Other users require at least one of the following privileges: + +* `ADMINISTRATION` +* `CAN_MANAGE_SPOTTER` + +The API endpoint doesn't allow users to delete the Analyst objects that are shared with them by another user. + +=== Request parameter + +Specify the ID of the Analyst to delete in the `analyst_identifier` path parameter. + +=== Request example + +[source,bash] +---- +curl -X POST \ + --url 'https://{cluster}/api/rest/2.0/ai/agent/analysts/{analyst_identifier}/delete' \ + -H 'Accept: application/json' \ + -H 'Authorization: Bearer {token}' +---- + +=== API Response + +Returns `200 OK` and an `AnalystDeleteResponse` object containing the `id` of the deleted Analyst. + + +== Related resources + +* xref:embed-spotter-analyst.adoc[Embed Spotter Analyst] +* xref:rest-api-v2-reference.adoc[REST API v2 reference] +* xref:privileges-and-roles.adoc[Privileges and roles] diff --git a/modules/ROOT/pages/whats-new.adoc b/modules/ROOT/pages/whats-new.adoc index d9fc73c1f..bf9e70a2e 100644 --- a/modules/ROOT/pages/whats-new.adoc +++ b/modules/ROOT/pages/whats-new.adoc @@ -1,7 +1,6 @@ = What's new :toc: true :toclevels: 1 - :page-title: What's new :page-pageid: whats-new :page-description: New features and enhancements @@ -22,6 +21,77 @@ This page lists new features, enhancements, and deprecated functionality introdu // *Status:* Current / Supported / Deprecated // *Affects:* Developers, Administrators, End Users // ============================================================ + + +== October 2026 + +**Release version**: ThoughtSpot Cloud 26.10.0.cl + +*Upgrade notes*: No breaking changes in this release. + +*Recommended SDK versions*: Visual Embed SDK v1.53.0 or later + +[.cl-table, cols="2,4", frame=none, grid=none] +|=== +a| +[.cl-label] +*Version 26.10.0.cl* + +a| + +[discrete] +==== Spotter Analyst + +Embed Spotter Analyst:: +You can now embed a single, pinned Spotter Analyst in your application using the Visual Embed SDK. The `spotterAnalystConfig.analystId` property in `SpotterEmbed` locks the embed to one governed Analyst experience. For more information, see xref:embed-spotter-analyst.adoc[Embed Spotter Analyst]. + + +REST API:: +Spotter Analysts are governed AI agents you can create, configure, and manage via the REST API. Four new endpoints are available under `/api/rest/2.0/ai/agent/analysts/` to create, search, update, and delete Analysts programmatically. Each Analyst is configured with a name, description, one or more data sources, and optional instructions, MCP connectors, and starter prompts. For more information, see xref:spotter-analyst-api.adoc[Spotter Analyst API]. + +--- + +[discrete] +==== Pinning Spotter conversations +Users can now pin Spotter conversations in the embedded view and also via REST API. so they appear at the top of the conversation list for quick access. For more information, see xref:embed-spotter-analyst.adoc[Embed Spotter Analyst] and xref:spotter-agent-conversation-mgmt-apis.adoc#update-conversation[Spotter conversation APIs]. +--- + +[discrete] +==== Feature management through APIs +ThoughtSpot now supports programmatic feature management with new REST APIv2 endpoints available under `/api/rest/2.0/configurations/features/`. Cluster and Org admins can search feature configurations, assign features to Orgs, and set feature values without using the link:https://docs.thoughtspot.com/cloud/latest/admin-portal-2#_feature_management[new Admin portal, window=_blank]. For more information, see xref:feature-management-api.adoc[Feature Management]. + +--- + +[discrete] +==== Liveboard enhancements +* *Contextual filtering in Liveboards* [earlyAccess eaBackground]#Early Access# ++ +Liveboard filters now have a three-tier filter hierarchy : Liveboard level, tab level, and group level. You can enable this feature in embedded Liveboards using the `isScopedLiveboardFilteringEnabled` parameter in the SDK. For more information, see xref:embed-pinboard.adoc#contextual-liveboard-filtering[Embed a Liveboard]. + +* *Host Events* ++ +** The `HostEvent.GetGroups` event returns group details for the Liveboard, and the `applicability` attribute on `HostEvent.UpdateFilters` and `HostEvent.UpdateParameters` scopes filter updates to a specific tab or group. For more information, see xref:embed-events.adoc[Events and app interactions]. +** The `HostEvent.OpenParameter` event opens the parameter panel for a specific parameter on the Liveboard. Accepts an optional `applicability` object to scope the action to a tab or group. + +* *Centralized filter modal* in Liveboards is now generally available and enabled by default on ThoughtSpot embedded instances. + +* *Column security rules on Liveboards* ++ +Liveboards that were previously blocked by Column Security Rules (CSR) now open and work normally, with column security fully enforced, including in embedded Liveboards. Filter values from inaccessible columns are masked instead of blocking the Liveboard, and scheduled Liveboard deliveries apply CSR separately for each recipient. For more information, see xref:data-security.adoc#csr-liveboards[Column security rules on Liveboards]. + +--- + +[discrete] +==== Visual Embed SDK +For information about the new features and enhancements introduced in Visual Embed SDK version 1.53.0, see xref:api-changelog.adoc[Visual Embed SDK changelog]. + +--- + +[discrete] +==== REST API +For information about REST API v2.0 enhancements in this release, see xref:rest-apiv2-changelog.adoc[REST API v2.0 changelog]. + +|=== + + == September 2026 **Release version**: ThoughtSpot Cloud 26.9.0.cl + @@ -866,4 +936,4 @@ For information about the new features and enhancements introduced in Visual Emb ==== REST API For information about REST API v2 enhancements, see xref:rest-apiv2-changelog.adoc[REST API v2.0 changelog]. -|=== +|=== \ No newline at end of file