Scenario support in the Ontology SDK (OSDK) is experimental and may not be available on your enrollment; be aware that the API surface described on this page is under active development and subject to change.
The Ontology SDK (OSDK) allows you to create and interact with Ontology scenarios directly from your application code. A scenario-scoped client behaves like a regular OSDK client: every object you read, every aggregation you compute, and every action you apply is automatically evaluated against the scenario's isolated sandbox rather than the main Ontology.
Scenario support is available in both the TypeScript and Python OSDK. The sections below describe how to perform the following operations in each language:
Scenario support is available in @osdk/client version 2.27.0 and later; generate a matching version of your SDK in Developer Console.
Custom widgets use the OSDK and can also create and interact with scenarios. Review Use Ontology SDK (OSDK) in a widget set for more information.
Use createScenario to create a new scenario, or withScenario to attach to an existing scenario by its RID. Both functions return a scenario-scoped client.
Copied!1 2 3 4 5 6 7 8 9 10import { createScenario, withScenario } from "@osdk/client/unstable-do-not-use"; // Create a new scenario. This is asynchronous because it calls the platform. const scenario = await createScenario(client); // Or attach to an existing scenario by RID. This is synchronous and makes no network call. const existingScenario = withScenario(client, "ri.actions..scenario.0000-..."); // Retrieve the scenario reference (RID) to persist or share. const scenarioRid: string = scenario.getScenarioReference();
If the base client is configured with a branch, the new scenario created by createScenario uses that branch as its base.
You can also attach to a scenario that is stored as a persisted scenario object. The primary key of a persisted scenario object is its scenario reference, so pass the object's $primaryKey to withScenario.
Copied!1 2 3// `scenarioObject` is a persisted scenario object you already have, for example from an object set query. // The scenario object's primary key is the scenario reference (RID). const scenario = withScenario(client, scenarioObject.$primaryKey);
The scenario client is callable exactly like a regular OSDK client. All reads are automatically scoped to the scenario.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13import { Restaurant } from "@my-app/sdk"; // Load a page of objects as they appear within the scenario. const page = await scenario(Restaurant).fetchPage(); // Filters and aggregations are also evaluated against the scenario. const filtered = await scenario(Restaurant) .where({ numberOfReviews: { $gte: 100 } }) .fetchPage(); const counts = await scenario(Restaurant).aggregate({ $select: { $count: "unordered" }, });
Apply an action through the scenario client to stage edits inside the scenario's sandbox. These edits do not affect the main Ontology until the scenario is merged.
Copied!1 2 3 4 5 6 7import { addReview } from "@my-app/sdk"; const result = await scenario(addReview).applyAction({ restaurantId: "restaurantId", reviewRating: 5, reviewSummary: "It was great!", });
Batch actions are not supported when applying actions within a scenario. Scenarios also cannot be nested within another scenario or combined with a transaction.
To merge a scenario, apply any action type configured with an Apply Scenario rule. Adding this rule to an action automatically exposes a scenario parameter of type scenarioReference. Pass the scenario client directly as the value of that parameter; the OSDK resolves it to the scenario reference automatically.
Copied!1 2 3 4 5import { applyScenario } from "@my-app/sdk"; // `applyScenario` is an action configured with an Apply Scenario rule, which // exposes a scenario parameter named `scenario`. await client(applyScenario).applyAction({ scenario });
The action and parameter names are specific to your Ontology. Review Merge scenarios for guidance on configuring the Apply Scenario rule on an action type.
The scenario client exposes methods to discover which objects and links were edited within a scenario. These results return sparse identifiers: only the $apiName and $primaryKey fields are populated. To load full property values, pass the primary keys back through the scenario client.
Use getEditedEntityTypes to discover which object and link types changed, then getEditedEntities to page through the edited objects of a given type, or editedEntitiesAsyncIter to stream them.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17import { Restaurant } from "@my-app/sdk"; // Discover which object types and link types were edited in the scenario. const { objectTypes, linkTypes } = await scenario.getEditedEntityTypes(); // Page through edited objects of a given object type. const editedPage = await scenario.getEditedEntities(Restaurant, { pageSize: 500 }); for (const obj of editedPage.data) { console.log(obj.$apiName, obj.$primaryKey); } // Or stream all edited objects of a given object type. The iterator auto-paginates and dedupes by primary key. for await ( const obj of scenario.editedEntitiesAsyncIter(Restaurant, { pageSize: 500 }) ) { console.log(obj.$primaryKey); }
To load full property values for the edited objects, re-fetch them through the scenario client.
Copied!1 2 3 4const keys = editedPage.data.map((obj) => obj.$primaryKey); const full = await scenario(Restaurant) .where({ $primaryKey: { $in: keys } }) .fetchPage();
Use getEditedLinkTypes, getEditedLinks, and editedLinksAsyncIter to inspect edited links. Each edited link is returned as a directed triple of source, target, and linkType. Only many-to-many links are returned; edited one-to-many links surface through getEditedEntities on the object type that owns the foreign key.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22import { Restaurant } from "@my-app/sdk"; // Discover which many-to-many link types for a given object type were edited. const editedLinkTypes = await scenario.getEditedLinkTypes(Restaurant); // Page through edited links for a given link type. const linksPage = await scenario.getEditedLinks(Restaurant, "sisterRestaurants", { pageSize: 200, }); for (const { source, target, linkType } of linksPage.data) { console.log(source.$primaryKey, "->", target.$primaryKey, `(${linkType})`); } // Or stream all edited links of a given link type. for await ( const { source, target } of scenario.editedLinksAsyncIter( Restaurant, "sisterRestaurants", ) ) { console.log(source.$primaryKey, "->", target.$primaryKey); }
Scenario support is available in Python OSDK version 2.209.0 and later, and is a beta feature: you must run scenario code within an AllowBetaFeatures context.
Use ScenarioClient.create to mint a new scenario, or the ScenarioClient constructor to attach to an existing scenario by its RID. Both return a scenario-scoped client.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14from foundry_sdk_runtime import AllowBetaFeatures from osdk import FoundryClient, ScenarioClient, UserTokenAuth with AllowBetaFeatures(): # Create a new scenario. This calls the platform to mint the scenario. scenario_client = ScenarioClient.create(client) # Or attach to an existing scenario by RID. scenario_client = ScenarioClient( client, scenario_rid="ri.actions..scenario.0000-..." ) # Retrieve the scenario reference (RID) to persist or share. scenario_rid = scenario_client.scenario_rid
The new scenario created by ScenarioClient.create inherits the ontology and branch of the base client. The base client passed to ScenarioClient must not itself be a scenario client.
You can also attach to a scenario that is stored as a persisted scenario object. The primary key of a persisted scenario object is its scenario reference, so pass the object's primary key to the ScenarioClient constructor.
Copied!1 2 3 4 5 6with AllowBetaFeatures(): # `scenario_object` is a persisted scenario object you already have, for example from a query. # The scenario object's primary key is the scenario reference (RID). scenario_client = ScenarioClient( client, scenario_rid=scenario_object.get_primary_key() )
Read and query objects through scenario_client.ontology.objects. All reads are automatically scoped to the scenario.
Copied!1 2 3 4 5 6with AllowBetaFeatures(): # Load a single object as it appears within the scenario. restaurant = scenario_client.ontology.objects.ExampleRestaurant.get("primaryKey") # Load a page of objects from within the scenario. page = scenario_client.ontology.objects.ExampleRestaurant.page(page_size=30)
Apply an action through the scenario client to stage edits inside the scenario's sandbox. These edits do not affect the main Ontology until the scenario is merged.
Copied!1 2 3 4 5 6 7 8 9from foundry_sdk_runtime.types import ActionConfig, ActionMode with AllowBetaFeatures(): scenario_client.ontology.actions.add_review( action_config=ActionConfig(mode=ActionMode.VALIDATE_AND_EXECUTE), restaurant_id="restaurantId", review_rating=5, review_summary="It was great!", )
To merge a scenario, apply any action type configured with an Apply Scenario rule. Adding this rule to an action automatically exposes a scenario parameter of type scenarioReference. Pass the scenario client (or its scenario_rid string) as the value of that parameter.
Copied!1 2 3 4 5 6 7 8 9 10from foundry_sdk_runtime.types import ActionConfig, ActionMode with AllowBetaFeatures(): # `apply_scenario` is an action configured with an Apply Scenario rule, which # exposes a scenario parameter named `scenario`. The action and parameter names # are specific to your Ontology. client.ontology.actions.apply_scenario( action_config=ActionConfig(mode=ActionMode.VALIDATE_AND_EXECUTE), scenario=scenario_client, # or scenario=scenario_client.scenario_rid )
Review Merge scenarios for guidance on configuring the Apply Scenario rule on an action type.
Listing the entities edited within a scenario is not yet supported in the Python OSDK. This capability will be added in a future release. To inspect edited entities today, use the TypeScript OSDK.