Bixby Developer Center

Guides

Modeling Concepts

A concept describes any "thing." It could represent a concrete object, such as coffee, flowers, or an airport. A concept can also be abstract, such as a day, flight, or order. Well-modeled concepts are essential to Bixby because the planner uses concept models as inputs and goals when executing plans. Concepts are comparable to data types and data structures in a programming language.

Primitive concepts represent simple types, like text or numbers. Structure concepts are more complex, representing records with named properties. Each property is itself a concept. A property is usually a primitive concept, but could be a structure concept itself.

Concepts can also model inheritance relationships. For example, a restaurant inherits the properties of a business, as shown in the following snippet from a structure:

structure (restaurant.Restaurant) {
description (A business who prepares and serves food to customers)
extends (business.Business)
...

As you start to build out your concepts, make sure that you have read Bixby's Design Guidelines so that your models follow a consistent user experience.

Primitive Concepts

Primitive concepts store simple data like text or numbers. There are seven data types for primitive concepts:

  • boolean: A binary variable with two possible values, true and false.
  • decimal: A floating-point number, positive or negative. This type allows a decimal part.
  • enum: An enumeration of a fixed set of possible values (symbols). Use this when it makes sense to list all the possible values in advance. (Also see structure enums.)
    Note

    If there is no vocab file, the enums will not be recognized by natural language.

  • integer: A whole number, positive or negative, with no decimals.
  • name: A Unicode string that is available to Bixby. Use this when the string might be part of natural language input, dialog, or vocabulary. Examples include business names, menu items, and movie titles.
  • qualified: A name that matches a regular expression. This is a good choice when you want to validate a string, and want it to be visible to Bixby, but can't enumerate every possible value in advance. The regex also makes it easier for Bixby to recognize valid values.
  • text: A Unicode string that is not available for use with vocabulary, although it can be displayed or passed to external services. This is good for URLs, blocks of XML or JSON, and large blocks of text such as movie or restaurant reviews.

Here are a few examples:

qualified (PhoneNumber) {
description (A string representing a phone number.)
regex-pattern ("\\+?1? ?-? ?((\\(\\d\\d\\d\\))|\\d\\d\\d)? ?-? ?\\d\\d\\d ?-? ?\\d\\d\\d\\d")
}
boolean (Confirmation) {
extends (core.Confirmation)
}

View master on GitHub

decimal (PlanetSize) {
description (A planet's diameter in miles)
}

View master on GitHub

enum (Type) {
description (Type of a shoe.)
symbol (Athletic)
symbol (Boot)
symbol (Casual)
symbol (Dance)
symbol (Formal)
symbol (Sandals)
}

View master on GitHub

integer (RollConcept) {
description (The result of a dice roll.)
}

View master on GitHub

name (PersonName) {
description ("The person's name. Ex: Jackie Chan")
}

View master on GitHub

text (Answer) {
description (The user's answer)
}

View master on GitHub

Well-modeled concepts use the right type for the right job. When primitive concepts are extended, the concepts must all be the same primitive type. In the boolean example above, core.Confirmation is a boolean primitive, because that is required for Confirmation to inherit from it.

Structure Concepts

A structure concept is a record-like type, similar to a struct or a key/value object in other programming languages. Structure concepts contain any number of properties. Each property of a structure must be a concept, not a primitive data type; see Properties, below.

In order for Bixby to use structures, you need an appropriate action model and corresponding function that outputs these structures.

For example, consider the following Order structure:

structure (Order) {
property (items) {
type (Item)
min (Optional)
max (Many)
}
property (orderNumber) {
type (OrderNumber)
min (Required)
}
property (totalPrice) {
type (Price)
min (Required)
}
property (holdTime) {
type (HoldTime)
min (Required)
}
features {
transaction
}
}

View master on GitHub

The following action model outputs an Order.

action (CreateOrder) {
type (BeginTransaction)
collect {
input (initialItems) {
type (InitialItems)
min (Required)
max (One)
default-init {
intent: goal: CreateItems
}
}
}
output (Order)
}

View master on GitHub

Here is the corresponding JavaScript:

import ZonedDateTime from './lib/zoned-date-time-polyfill.js';
import config from 'config';
//CreateOrder
export default function ({ initialItems, $vivContext }) {
ZonedDateTime.setVivContext($vivContext);
return {
items: initialItems.items,
totalPrice: calculateTotalPrice(initialItems.items),
orderNumber: 23343,
holdTime: ZonedDateTime.now('UTC')
.plusSeconds(parseInt(config.get('hold_time')))
.getMillisFromEpoch(),
};
}

function calculateTotalPrice(items) {
var totalPrice = 0;
for (var i = 0; i < items.length; i++) {
totalPrice += items[i].shirt.price.value * items[i].quantity;
}
return {
value: totalPrice,
currencyType: {
prefixSymbol: '$',
currencyCode: 'USD',
},
};
}

View master on GitHub

Properties

Properties define a "has-a" relationship between concepts. For example, a business has an address; address could be defined as a primitive concept of type name, and the Business structure concept could include address as a property.

Properties must be semantically meaningful, so they can be useful as input to other concepts or actions. Because of this, every property must be a concept. For example, you can't define a Magnitude property directly as type (decimal) in a structure. Instead, define a Magnitude primitive concept using the decimal data type:

decimal (Magnitude) {
description (The magnitude of an earthquake)
features {
recognized-range {
min-value(0)
max-value(12)
}
}
}

View master on GitHub

Then use type (Magnitude) for your property in the structure:

structure (Earthquake) {
description (An earthquake)

property (title) {
type (Title)
min (Optional) max (One)
}
property (dateTime) {
type (EarthquakeDateTime)
min (Optional) max (One)
}
property (location) {
type (EarthquakeLocation)
min (Optional) max (One)
}
property (magnitude) {
type (Magnitude)
min (Optional) max (One)
}
}

View master on GitHub

Note

Before creating your own concepts for values like location, dates, times, and currency, see if you can import a library capsule that provides the functionality you need. For example, if you need a Latitude property, you can import the viv.geo library capsule, which includes not only a predefined Latitude concept but higher-level geographical concepts and actions. In addition, concepts from library capsules sometimes include appropriate dialog for values (for example, viv.geo will format Latitude values as degrees north or south), and might include vocabulary for name primitives (for example, viv.geo includes US state abbreviations such as CA and NY).

Another use of library capsules is defining structure properties by using the primitive concepts in the viv.core library as types:

structure (Earthquake) {
property (title) {
type (viv.core.Text)
min (Optional) max (One)
}
property (magnitude) {
type (viv.core.Decimal)
min (Optional) max (One)
}
}

However, if you need to directly refer to a property, including using them in Bixby Views or as inputs to actions, you must define as their own primitive concepts as described above. Also, not all possible types have corresponding concepts in viv.core. For instance, if you need to distinguish between name and text types, you'll have to define your own primitive concepts to do so.

Cardinality

By default, each property is optional and single in cardinality, meaning it can optionally have a single value. Optionality is set with the min keyword; cardinality is set with max.

You can state the default values explicitly with min (Optional) and max (One). To allow any number of values for a property, specify max (Many). To require at least one value, specify min (Required). If a property allows more than one value, all of the values must be of the property's declared type.

Here's an example Hotel structure with several properties:

structure (Hotel) {
property (name) {
type (HotelName)
min (Required) max (One)
}
property (rating) {
type (HotelRating)
min (Required) max (One)
}
property (lowRate) {
type (HotelLowRate)
min (Required) max (One)
}
property (location) {
type (geo.GeoPoint)
min (Optional) max (One)
}
property (reviewCount) {
type (HotelReviewCount)
min (Optional) max (One)
}
property (images) {
type (core.BaseImage)
min (Optional) max (Many)
}
property (amenities) {
type (HotelAmenity)
min (Optional) max (Many)
}
}

View master on GitHub

The property rating must have a single HotelRating value. The reviewCount property is optional, but if present, it must be a HotelReviewCount and have a max of one. However, the images and amenities properties are also optional but can have multiple values.

A property will normally only store unique values: if your capsule adds a value to a max (Many) node that is equivalent to a value already in that node, the values will be automatically merged. If the amenities property for the Hotel structure had the values ["Wifi", "Spa", "Swimming Pool"], you could add the value "Kid-friendly" to it. However, if you added the value "Spa", it would automatically be merged with the existing value "Spa", and the values in the amenities property would remain unique. Read about Merging and Equivalence for more about this, as well as how this behavior can be overridden.

Property Visibility

There are times when you might want the properties within concepts to be visible or invisible to the Planner.

For example, let's say you're defining the GeoPoint structure. This contains latitude and longitude properties, which you probably wouldn't expose independently of the rest of the structure. But it might make sense to declare the timeZone property with visibility(Public). That helps if some execution plan includes an action with a time.TimeZoneId input and the system already has a GeoPoint input.

structure (GeoPoint) {
description (A geographic point.)
property (latitude) {
type (Latitude)
min (Required)
}
property (longitude) {
type (Longitude)
min (Required)
}

property (timeZone) {
type (time.TimeZoneId)
visibility (Public)
min (Optional) max (One)
}
}

Here's an example of an execution graph for the utterance, "get the timezone in Seoul, South Korea," in which NamedPoint contains a property point of type GeoPoint:

Execution graph example for timezone request

Likewise, for a stock lookup feature, certain commonly used properties such as the stock exchange (stockExchange) and stock symbol (StockSymbol) should be available throughout the entire plan:

structure (ExchangeListing) {
description (Listings on various exchanges)
property (stockExchange) {
type (Exchange)
min (Required) max (One)
visibility (Public)
}
property (companyName) {
type (CompanyName)
min (Required) max (One)
visibility (Public)
}
property (stockSymbol) {
type (StockSymbol)
min (Required) max (One)
visibility (Public)
}
property (ipoYear) {
type (IpoYear)
}
property (companyUrl) {
type (entity.EntityUrl)
}
}

Here is an execution graph that illustrates this usage:

Execution graph example for stock lookup

If a property has Default visibility, subsequent actions won't see it separately from its parent structure. But the Planner can still see the final goal, and so can a route or a sort value. For example, Weather is a structure with a DayHighTemperature property with Default visibility. If a user asks "What was the high temperature today?" that becomes the plan's final goal, and gains direct access to the DayHighTemperature property.

Execution graph example for temperature request

You could prevent this by setting visibility (Private), prohibiting the use of the property anywhere in a plan. Private properties should be properties that a user would never want to use or that are only used internally.

Structure Enums

A Structure Enum is the structure counterpart to the the enum data type used in primitive concepts. Both primitive and structure enums have a value chosen from a pre-defined list of constants, but a structure enum's constants set all the properties in the structure at once. It composes properties into a single enumeration list.

Here is an example of the syntax for a structure enum:

structure-enum (CurrencyType) {
property (currencyCode) {
type (CurrencyCode)
}
property (prefixSymbol) {
type (PrefixSymbol)
}
constant: CurrencyType {
prefixSymbol: ($)
currencyCode: (USD)
}
constant: CurrencyType {
prefixSymbol: ()
currencyCode: (EUR)
}
// ... additional currency types ...
}

This structure enum contains two properties, prefixSymbol and currencyCode, and the enumeration sets them together:

  • prefixSymbol: $, currencyCode: USD
  • prefixSymbol: €, currencyCode: EUR

As you can see, this CurrencyType structure-enum is important in any capsule where different currency is required and the appropriate currency needs to be used.

Relationships Between Concepts

Before creating new concepts, see if you can reuse or extend any existing concepts. This is very powerful. Besides saving time, you will benefit from existing training.

You have already seen how to reuse existing concepts as properties of a new concept. That's useful, but you can also define relationships between concepts.

Extension

You can extend a parent concept with a new child concept. If the parent concept is a structure with properties, the child concept inherits those properties as well. Then you can define new properties specific to the child concept. This is like inheritance in many programming languages and represents an "is-a" relationship; it describes a parent-child or subset relationship. You can extend both primitive concepts and structure concepts. You can also extend multiple concepts at the same time.

For example, a restaurant is a business. Like any business, it has a phone number, but it can also have a menu. All restaurants are businesses, but not all businesses are restaurants. Restaurants have characteristics that not all other businesses have. Because of this, you can treat any restaurant as a business. But you can't treat all businesses as restaurants.

Here are some other examples:

// A DeliveryRestaurant is both a Restaurant and a
// Vendor (that has a catalog you can buy from, like a menu)
structure (DeliveryRestaurant) {
extends (viv.restaurant.Restaurant)
extends (viv.order.Vendor)
}
// A Country is a special type of AdministrativeDivision
structure (CountryDivision) {
extends (AdministrativeDivision)
property (countryCode2) {
type (ISOCountryCode2)
min (Optional)
max (One)
}
property (countryCode3) {
type (ISOCountryCode3)
min (Optional)
max (One)
}
}
structure (ThisPlanet) {
role-of (Planet)
//extends will allow projections as goals description
extends (Planet)
}

View master on GitHub

When you extend a structure concept, you can also choose to override a parent property. You can use this to bind a particular value. This example for Restaurant inherits BusinessCategory from business.Business, but its value will always be "Restaurant."

structure (Restaurant) {
description (A business who prepares and serves food to customers)
extends (business.Business)
property (name) {
override type (RestaurantName)
}
property (category) {
override bind (Restaurant)
}
property (restaurantStyle) {
type (RestaurantStyle)
max (Many)
}
// ... more properties ...
}

You can also override the type of a property to a more specific type. In the last example, the name property of a Restaurant is specified as RestaurantName. This is more specific than the BusinessName used by the parent concept. This only works if RestaurantName extends BusinessName.

When overriding a property you can also change the minimum cardinality, but only from Optional to Required.

Role Assignment

Suppose your capsule has a FindFlight action which takes two airports: a departure airport and an arrival airport. You have an Airport concept. But you can't give a type of Airport to more than one input in your action. You could make ArrivalAirport and DepartureAirport concepts that extend Airport, but this would make planning actions more complicated: you want any action that instantiates an Airport concept to be able to use that Airport for either departure or arrival based on context. To do this, you can give ArrivalAirport and DepartureAirport a role-of the Airport concept.

structure (ArrivalAirport) {
role-of (Airport)
}

A role lets a concept take on different behaviors based on its context. The context is the only difference between a concept and its parent. With the role of Airport assigned to ArrivalAirport and DepartureAirport, then any Airport created by Bixby in a previous plan step can be converted into an ArrivalAirport or a DepartureAirport when it's needed. This way, any airport could be used for arrival or departure based on flight itineraries.

Here's how a corresponding execution graph for flight booking looks:

Execution graph showing roles

Notice that both DepartureAirport and ArrivalAirport first start as Airport, after which they are given new roles.

Note

You cannot add new properties to a concept using role-of. If you need to create a child concept that adds new properties to its parent, you should use extends instead.

You can add new symbols to an enum with extends, but not with role-of. An enum can extend multiple concepts or have multiple roles only if all the target enum concepts have identical symbol sets.

Concept Features

When you flag a concept with concept features, you are flagging it so that the Bixby platform can treat it in a special way. This special treatment ranges from marking a concept as something stored with a user profile to not storing a value at all. Concept features offer ways to manage user preferences, privacy, or security.

  • profile-stored: Associate the concept value with the user profile. Store and retrieve as needed.

  • transient: Do not store the concept value. Do not preserve it across execution context.

  • transaction: Treat a concept as a "transaction draft", which you can use for inputs to transaction and commit actions.

  • activity: Represents "transaction records", which are the result of completing commit-type actions. They can also be used as inputs to activity actions.

  • recognized-range: Used with decimal and integer concepts to set a range of acceptable values with a lower bound (min-value) and an upper bound (max-value).

The transaction and activity features are transactional features, so after you mark a concept with a transactional feature, you must also define the corresponding state in corresponding support files (*.transaction.bxb for transaction and *.activity.bxb for activity). You can read more in Transactional Workflows.

Profile-Stored Concepts

Sometimes you know that the user will want to reuse a concept value. It might be the user's name, billing address, or airline seat preferences. Mark these concepts with the features key profile-stored, and users will have the option to save their values for reuse.

structure (FlightPreferences) {
description (Used to store user flight preferences.)
features {
profile-stored { max (Many) }
}
property (seat) {
type (AirplaneSeatType)
}
property (carrier) {
type (CarrierCode)
}
}

Storing these values is optional, and Bixby prompts the user for approval.

You might want to store certain concept values as singletons, where there can only be one value at a time for the concept. For example, when booking a flight, a single passenger's name must appear on each ticket. Mark such concepts with profile-stored with a max cardinality of One, to ensure that the profile is unique and the restriction is enforced.

Transient Concepts

Some concepts should never have their values stored and re-used across execution contexts. For example, the user's current location should always be determined every time that value is accessed.

Give a concept the transient feature to ensure that Bixby will never store or reuse the concept values. Transient concepts will not be re-used from the historical context of a conversation. The library concept geo.CurrentLocation has the transient feature, as do most of the concepts within the DateTime library.

You can see another example of transient being used with the SearchTerm concept in the Fact sample capsule prototype. For example, if the user asks "Tell me a fact about dogs", then "dogs" would be tagged as the transient SearchTerm. If the user follows up that utterance with "Tell me another fact", the SearchTerm will be dropped and not carried over into the follow-up's conversational context. Bixby would then return a different fact not necessarily about dogs.