Frame Tools

Reshape, query, and combine lists of records โ€” a columnar data operations layer for in-flight data.

Frame tools are pure deterministic operations on lists of record maps. There are no external calls, no AI generation, and no credit cost. Every response includes a deterministic receipt under _meta.datagrout. Frame tools compose naturally with each other and with the Math suite via flow.into, and accept cache_ref outputs from auto-paginated integration tools so you can operate on large datasets without re-transmitting them. All Frame tools are available at data-grout@1/frame.*@1.


frame.select@1

Keep, rename, or drop columns from a list of records.

Parameters

Parameter Type Required Default Description
payload array conditionally โ€“ List of record maps. Provide either payload or cache_ref, not both
cache_ref string conditionally โ€“ Cache reference from a prior auto-paginated tool call
columns array | object no โ€“ Fields to keep. A list keeps only those fields; a { "old_name": "new_name" } map renames while selecting
drop array no โ€“ Field names to remove. Applied after columns if both are given

Example: keep specific columns

{
  "name": "data-grout@1/frame.select@1",
  "arguments": {
    "payload": [
      { "name": "Alice", "email": "alice@acme.com", "role": "admin", "internal_id": 1 },
      { "name": "Bob", "email": "bob@acme.com", "role": "user", "internal_id": 2 }
    ],
    "columns": ["name", "email", "role"]
  }
}

Response:

{
  "records": [
    { "name": "Alice", "email": "alice@acme.com", "role": "admin" },
    { "name": "Bob", "email": "bob@acme.com", "role": "user" }
  ],
  "count": 2
}

Example: rename columns

{
  "name": "data-grout@1/frame.select@1",
  "arguments": {
    "payload": [ "..." ],
    "columns": { "name": "customer_name", "email": "contact_email" }
  }
}

frame.filter@1

Filter rows using declarative predicate conditions. All conditions in the where array must match (AND logic).

Parameters

Parameter Type Required Default Description
payload array conditionally โ€“ List of record maps
cache_ref string conditionally โ€“ Cache reference from a prior paginated call
where array yes โ€“ List of condition objects. Each has field, op, and (for most ops) value

Filter operators

Operator Description
eq / neq Equals / not equals
gt / gte / lt / lte Numeric comparisons
in / not_in Value is in (or not in) a list
contains String contains substring
starts_with / ends_with String prefix / suffix match
is_null / not_null Null check (no value needed)

Example

{
  "name": "data-grout@1/frame.filter@1",
  "arguments": {
    "payload": [ "..." ],
    "where": [
      { "field": "status", "op": "eq", "value": "active" },
      { "field": "amount", "op": "gte", "value": 1000 }
    ]
  }
}

Response:

{
  "records": [ "...matched rows..." ],
  "count": 14,
  "filtered": 38
}

frame.sort@1

Sort records by one or more fields with per-field direction control.

Parameters

Parameter Type Required Default Description
payload array conditionally โ€“ List of record maps
cache_ref string conditionally โ€“ Cache reference
by array yes โ€“ List of sort specs. Each has field (string) and optional dir ("asc" or "desc", default "asc")

Example

{
  "name": "data-grout@1/frame.sort@1",
  "arguments": {
    "payload": [ "..." ],
    "by": [
      { "field": "revenue", "dir": "desc" },
      { "field": "name", "dir": "asc" }
    ]
  }
}

Response:

{
  "records": [ "...sorted rows..." ],
  "count": 52
}

frame.group@1

Group rows by one or more fields and aggregate other fields. Returns one record per group.

Parameters

Parameter Type Required Default Description
payload array conditionally โ€“ List of record maps
cache_ref string conditionally โ€“ Cache reference
by string | array yes โ€“ Field name or list of field names to group by
agg array no โ€“ List of aggregation specs. Each has field, op, and optional as (output column name)

Aggregation operators

Operator Description
sum Sum of numeric values
mean Arithmetic mean
count Row count per group
count_distinct Count of distinct values
min / max Minimum / maximum value
first / last First or last value in group order
list Collect all values into an array

Example

{
  "name": "data-grout@1/frame.group@1",
  "arguments": {
    "payload": [
      { "customer": "Acme", "amount": 500, "status": "paid" },
      { "customer": "Globex", "amount": 300, "status": "pending" },
      { "customer": "Acme", "amount": 200, "status": "paid" }
    ],
    "by": "customer",
    "agg": [
      { "field": "amount", "op": "sum", "as": "total" },
      { "field": "amount", "op": "count", "as": "invoice_count" }
    ]
  }
}

Response:

{
  "records": [
    { "customer": "Acme", "total": 700, "invoice_count": 2 },
    { "customer": "Globex", "total": 300, "invoice_count": 1 }
  ],
  "count": 2,
  "groups": 2
}

frame.pivot@1

Reshape a long dataset into a wide format. Distinct values of one column become new column headers.

Parameters

Parameter Type Required Default Description
payload array conditionally โ€“ List of record maps in long format
cache_ref string conditionally โ€“ Cache reference
index string yes โ€“ Field whose values form the row identity
columns string yes โ€“ Field whose distinct values become the new column headers
values string yes โ€“ Field whose values fill the new columns
agg string no "first" Aggregation to apply when multiple rows map to the same cell: "first", "last", "sum", "mean", "count", "list"

Example

{
  "name": "data-grout@1/frame.pivot@1",
  "arguments": {
    "payload": [
      { "region": "North", "quarter": "Q1", "revenue": 42000 },
      { "region": "North", "quarter": "Q2", "revenue": 48000 },
      { "region": "South", "quarter": "Q1", "revenue": 31000 },
      { "region": "South", "quarter": "Q2", "revenue": 35000 }
    ],
    "index": "region",
    "columns": "quarter",
    "values": "revenue"
  }
}

Response:

{
  "records": [
    { "region": "North", "Q1": 42000, "Q2": 48000 },
    { "region": "South", "Q1": 31000, "Q2": 35000 }
  ],
  "count": 2,
  "pivot_columns": ["Q1", "Q2"]
}

frame.slice@1

Paginate or take a top-N subset of records by offset and limit.

Parameters

Parameter Type Required Default Description
payload array conditionally โ€“ List of record maps
cache_ref string conditionally โ€“ Cache reference
offset integer no 0 Number of records to skip
limit integer no 25 Maximum number of records to return

Example

{
  "name": "data-grout@1/frame.slice@1",
  "arguments": {
    "cache_ref": "pg_abc123",
    "offset": 50,
    "limit": 25
  }
}

Response:

{
  "records": [ "...25 records..." ],
  "count": 25,
  "offset": 50,
  "total": 842
}

frame.join@1

Join two lists of records on one or more shared key fields. For conflicting non-key fields, the left value wins and the right field is prefixed with right_.

Parameters

Parameter Type Required Default Description
left array conditionally โ€“ Left-side record list. Provide left or left_cache_ref
right array conditionally โ€“ Right-side record list. Provide right or right_cache_ref
left_cache_ref string conditionally โ€“ Cache reference for left-side data
right_cache_ref string conditionally โ€“ Cache reference for right-side data
on string | array yes โ€“ Key field name or list of key field names to join on
type string no "inner" Join type: "inner", "left", "right", "outer"

Example

{
  "name": "data-grout@1/frame.join@1",
  "arguments": {
    "left": [
      { "id": "c1", "name": "Acme Corp", "tier": "enterprise" },
      { "id": "c2", "name": "Globex", "tier": "growth" }
    ],
    "right": [
      { "id": "c1", "open_invoices": 3, "overdue_amount": 4500 },
      { "id": "c3", "open_invoices": 1, "overdue_amount": 800 }
    ],
    "on": "id",
    "type": "left"
  }
}

Response:

{
  "records": [
    { "id": "c1", "name": "Acme Corp", "tier": "enterprise", "open_invoices": 3, "overdue_amount": 4500 },
    { "id": "c2", "name": "Globex", "tier": "growth", "open_invoices": null, "overdue_amount": null }
  ],
  "count": 2
}

Using cache_ref with frame tools

Every tool call result is now cached and assigned a cache_ref at _meta.datagrout.cache_ref. Frame tools can reference this ref to operate on cached data without re-transmitting it through the LLM context. See also the data.* tools for general JSON structure manipulation with cache_ref support.

{
  "name": "data-grout@1/flow.into@1",
  "arguments": {
    "plan": [
      {
        "id": "fetch",
        "tool": "quickbooks@1/get-all-invoices@1",
        "args": { "limit": 10000 }
      },
      {
        "id": "group",
        "tool": "data-grout@1/frame.group@1",
        "args": {
          "cache_ref": "$fetch._cache_ref",
          "by": "customer_name",
          "agg": [
            { "field": "amount", "op": "sum", "as": "total_revenue" },
            { "field": "id", "op": "count", "as": "invoice_count" }
          ]
        }
      },
      {
        "id": "top10",
        "tool": "data-grout@1/frame.sort@1",
        "args": {
          "payload": "$group.records",
          "by": [{ "field": "total_revenue", "dir": "desc" }]
        }
      },
      {
        "id": "display",
        "tool": "data-grout@1/frame.slice@1",
        "args": { "payload": "$top10.records", "limit": 10 }
      }
    ]
  }
}