ModelWorks logoModelWorks
JSON Transform

JSON Transform

Reshape arrays, objects, and strings in memory using a chain of declarative operations

Introduction to JSON Transform

The circuit.core.transform.json primitive evaluates a source selector against memory and runs an ordered list of operations over the resulting value. Each operation consumes the output of the previous one, so you can compose array, object, and string transformations into a single pipeline without writing custom code.

Common uses include preparing message arrays for LLM calls, normalising fetched API payloads, and projecting objects down to the fields a downstream step needs.


Step Definition

JSON
"steps": [
  {
    "name": "prepare_messages",
    "description": "Inject or override the system prompt in messages array",
    "function": "circuit.core.transform.json",
    "input": {
      "source": "${{ messages }}",
      "operations": [
        { "type": "filter",  "options": { "expression": "role != `system`" } },
        {
          "type": "unshift",
          "options": {
            "items": [{ "role": "system", "content": "${{ prompts.system_prompt }}" }]
          }
        }
      ]
    },
    "outputs": [
      {
        "name": "prepared_messages",
        "description": "Messages array with system prompt injected",
        "value": "${{ prepare_messages.output.transformed_result }}"
      }
    ]
  }
]

input Properties

FieldTypeRequiredDescription
sourcestringYesSelector expression (${{ ... }}) for the value to transform.
operationsarray<object>YesOrdered list of operations. Each entry is { "type": "<op>", "options": { ... } }.

conditions (optional)

Like other primitives, this step accepts a top-level conditions array. If any condition evaluates to false, the step is skipped and transformed_result is set to null.

JSON
"conditions": [
  { "expression": "${{ messages != `null` }}" }
]

Output Shape

After execution the step exposes the following on its output object:

SelectorDescription
${{ <step>.output.transformed_result }}Final value after all operations have been applied. Use this.
${{ <step>.output.input }}Resolved source value before any operations ran.
${{ <step>.output.operations_original }}Operations as authored, with selectors unresolved.
${{ <step>.output.operations_evaluated }}Operations with all ${{ ... }} selectors resolved against memory.

Selector Resolution Inside Options

Only specific fields within an operation's options are selector-evaluated before that operation runs. These fields are: push.items, unshift.items, insertAt.items, concat.arrays, merge.objects, and replaceMatching.with. All other fields are used as literal values.

Both of these forms are valid and produce the same result:

JSON
{ "type": "unshift", "options": { "items": "${{ new_system_messages }}" } }
JSON
{
  "type": "unshift",
  "options": {
    "items": [{ "role": "system", "content": "${{ prompts.system_prompt }}" }]
  }
}

Operation Reference

Operations are grouped by the kind of value they expect as input. Mismatched input types (e.g., running pick on an array) cause the step to record an error and leave transformed_result empty.

Array Operations

OperationDescriptionOptions
sliceExtract a portion of an arraystart, end (optional)
popRemove elements from the endn (default: 1)
pushAdd elements to the enditems
shiftRemove elements from the beginningn (default: 1)
unshiftAdd elements to the beginningitems
replaceAtReplace element at indexindex, value
insertAtInsert elements at indexindex, items
removeAtRemove elements at indicesindices
reverseReverse the array ordernone
sortSort the arraykey (optional), order (default asc)
uniqueRemove duplicate elementskey (optional)
flattenFlatten nested arraysdepth (default: 1)
filterKeep elements matching a conditionexpression
mapTransform each elementexpression (JMESPath)
findReturn first matching elementexpression
findIndexReturn index of first match (or -1)expression
concatConcatenate additional arraysarrays
groupByGroup into an object keyed by fieldkey
chunkSplit into fixed-size chunkssize
replaceMatchingReplace elements matching a conditioncondition, with, mode (default all)

Object Operations

OperationDescriptionOptions
pickKeep only the given keyskeys
omitRemove the given keyskeys
mergeDeep-merge objects into the currentobjects
keysReturn the object's keys as an arraynone
valuesReturn the object's values as an arraynone
entriesReturn [key, value] pairsnone
fromEntriesConvert [key, value] pairs to an objectnone
setSet a value at a dot-pathpath, value
unsetRemove values at dot-pathspaths
renameKeyRename a single top-level keyfrom, to
defaultsFill missing keys from a defaults objectdefaults

String Operations

OperationDescriptionOptions
splitSplit a string into an arrayseparator, limit (optional)
joinJoin an array into a stringseparator
trimStrip whitespace on both endsnone
trimStartStrip leading whitespacenone
trimEndStrip trailing whitespacenone
substringExtract a substringstart, end (optional)
toLowerCaseLowercase the stringnone
toUpperCaseUppercase the stringnone
replaceReplace the first matchpattern, replacement
replaceAllReplace all matchespattern, replacement
padStartPad on the leftlength, pad_char (default: space)
padEndPad on the rightlength, pad_char (default: space)
repeatRepeat the string n timescount

Where to next

  • Expressions — the filter mini-syntax (with backticks) and the JMESPath context (item, @) used by map, find, findIndex, and replaceMatching.
  • Examples — full pipelines: system-prompt injection, top-N filter→sort→slice→pick, and config normalisation.
On this page

On this page