sdk.exec

sdk.exec(command: string): Promise<{ stdout: string, stderr: string }>

Runs a shell command inside the container asynchronously. Returns the stdout and stderr output of the process.

Example:

Executing the following code in the command template:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    await sdk.exec('mkdir test-directory')
    const { stdout, stderr } = await sdk.exec('ls')

    sdk.log('stdout is:\n', stdout)
    sdk.log('stderr is:\n', stderr)
}

main()

will create a folder named test-directory in the container, and logs the following text.

stdout is:
demo.js
index.js
node_modules
package-lock.json
package.json
test-directory

stderr is:

sdk.getHostOS

sdk.getHostOS(): string

Returns the Operating System the host is running on. For remote ops, will return "unknown" as no host is accessible in the remote environment.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    const hostOs = sdk.getHostOS()

    sdk.log("Host's os is:", hostOs)
}

Output:

Host's os is: darwin

sdk.homeDir

sdk.homeDir(): string

Returns the home directory of the host machine.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  const homeDir = sdk.homeDir()

  console.log("Host's home directory is:", homeDir)
}

Output:

Host's home directory is: /root

sdk.log

sdk.log(...args: any[]): void

Logs to the console in in a standardized way. Will not be relayed to
the user in a remote environment (use ux.print for that).

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  sdk.log('I am a log!', '\nI am too!')
}

Output:

I am a log!
I am too!

sdk.getStatePath

sdk.getStatePath(): string

Returns the path of the state directory. The contents of this directory are persistent through a workflow, including on remote.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  const statePath = sdk.getStatePath()

  sdk.log('The state path is:', statePath)
}

Output:

The state path is: /root/.config/@cto.ai/ops/superman/test-op/00000000-1111-2222-3333-444444444444

sdk.getConfigPath

sdk.getConfigPath(): string

Returns the path of the config directory. This directory is persistent across multiple runs of the op if the mountHome option in ops.yml is set to true.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  const configPath = sdk.getConfigPath()

  sdk.log('The config path is:', configPath)
}

Output:

The config path is: /root/.config/@cto.ai/ops/superman/test-op

sdk.setState

sdk.setState(key: string, value: any): Promise<void>

Stores a key-value pair in the workflow-local state. If the key is already present, the value will be replaced with the one provided.

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
  const key = 'test-key'

  // state = {}
  const initialState = await sdk.getState(key)
  sdk.log('Initial state', initialState)

  // state = { test-key: 'Value one' }
  await sdk.setState(key, 'Value one')
  const insertedState = await sdk.getState(key)
  sdk.log('Inserted state', insertedState)

  // state = { test-key: 'Value two' }
  await sdk.setState(key, 'Value two')
  const updatedState = await sdk.getState(key)
  sdk.log('Updated state', updatedState)
}

Output:

Initial state undefined
Inserted state Value one
Updated state Value two

sdk.getState

sdk.getState(key: string): Promise<any>

Gets the value that is saved under the given key in the workflow-local state, or undefined if the key is not set.

Example:

See sdk.setState above

sdk.setConfig

sdk.setConfig(key: string, value: any): Promise<void>

Stores a key-value pair in the persistent configuration. If the key is already present, the value will be replaced with the one provided. This function requires mountHome: true in the ops.yml

Example:

import { sdk } from '@cto.ai/sdk'

const main = async () => {
    const key = 'test-key'

    // config = {}
    const initialConfig = await sdk.getConfig(key)
    sdk.log('Initial config', initialConfig)

    // config = { test-key: 'Value one' }
    await sdk.setConfig(key, 'Value one')
    const insertedConfig = await sdk.getConfig(key)
    sdk.log('Inserted config', insertedConfig)

    // config = { test-key: 'Value two' }
    await sdk.setConfig(key, 'Value two')
    const updatedConfig = await sdk.getConfig(key)
    sdk.log('Updated config', updatedConfig)
}

Output:

Initial config undefined
Inserted config Value one
Updated config Value two

sdk.getConfig

sdk.getConfig(key: string): Promise<any>

Gets the value that is saved under the given key in the persistent configuration, or undefined if the key is not set.

Example

See sdk.setConfig above

sdk.track

sdk.track(tags, metadata): Promise<any>

Send an analytics tracking event to the Ops Platform.

  • tags: (String || String[]) Tags for the event you want to track
  • metaData: (Object) Data you want to be tracked

Terminology

Config

The SDK provides persistent config so that your op can store data on the host between executions. This can be accessed with the sdk.setState and sdk.getState functions.

  • The config is stored in a JSON file at the host path ~/.config/@cto.ai/ops/${username}/${opName}/config.json
  • Configs are persisted if the code is executed multiple times
  • Each op has its own config, and cannot affect any other op's config

State

The SDK provides a mechanism for maintaining state through the different steps of a workflow. Anything stored in the state directory (found with sdk.getStatePath) will be available in later steps. Additionally, the SDK provides key/value storage in the state similar to the config.

  • Locally, the state is stored in the following directory: ~/.config/@cto.ai/ops/${username}/${opName}/${runId}, with the key/value store saved in `state.json therein.
  • Each execution of a workflow is a different run and will have a different state, which will initially be blank.