Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions specification/v0_9/docs/a2ui_custom_functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Extending A2UI with Custom Functions

A2UI functions are designed to be extensible. Third-party developers can define
their own
function catalogs while preserving strict validation for the standard set.

This guide demonstrates how to create a `custom_catalog.json` that adds a string
`trim` function and a hardware query function (`getScreenResolution`).

## 1. Define the Custom Catalog

Create a JSON Schema file (e.g., `custom_catalog.json`) that defines your
function parameters.

Use the `functions` property to define a map of function schemas.

```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/custom_catalog.json",
"title": "Custom Function Catalog",
"description": "Extension catalog adding string trimming and screen resolution functions.",
"functions": {
"trim": {
"type": "object",
"properties": {
"call": { "const": "trim" },
"returnType": { "const": "string" },
"args": {
"type": "array",
"minItems": 1,
"maxItems": 2,
"prefixItems": [
{
"$ref": "https://a2ui.dev/specification/v0_9/common_types.json#/$defs/DynamicString",
"description": "The string to trim."
},
{
"$ref": "https://a2ui.dev/specification/v0_9/common_types.json#/$defs/DynamicString",
"description": "Optional. A set of characters to remove. Defaults to whitespace."
}
]
}
},
"required": ["call", "args"]
},
"getScreenResolution": {
"type": "object",
"properties": {
"call": { "const": "getScreenResolution" },
"returnType": { "const": "array" },
"args": {
"type": "array",
"minItems": 0,
"maxItems": 1,
"prefixItems": [
{
"$ref": "https://a2ui.dev/specification/v0_9/common_types.json#/$defs/DynamicNumber",
"description": "Optional. The index of the screen to query. Defaults to 0 (primary screen)."
}
]
}
},
"required": ["call"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with other function definitions in this document and in standard_catalog.json, the getScreenResolution function example should require the args property. Even when a function has optional or no arguments, requiring an args property (which can be an empty array) makes the function call structure uniform and more predictable for implementers.

Suggested change
"required": ["call"]
"required": ["call", "args"]

}
}
}
```

## 2. Make the functions available

The `FunctionCall` definition refers to a [catalog-agnostic reference](a2ui_protocol.md#the-standard-catalog).
In your catalog, you simply need to define the `anyFunctions` reference:
```json
{
"$defs": {
"anyFunction": {
"oneOf": [
{"$ref": "#/functions/trim"},
{"$ref": "#/functions/getScreenResolution"}
]
}
}
}
```

If you want to incorporate functions defined in the [`standard_catalog.json`],
those can be added too:
```json
{
"$defs": {
"anyFunction": {
"oneOf": [
{"$ref": "#/functions/trim"},
{"$ref": "#/functions/getScreenResolution"},
{"$ref": "catalog.json#/$defs/anyFunction" }
]
}
}
}
```

## How Validation Works

When a `FunctionCall` is validated:

1. **Discriminator Lookup:** The validator looks at the `call` property of the
object.
2. **Schema Matching:**
* If `call` is "length", it matches `Functions` -> `length`
and validates the arguments against the length rules.
* If `call` is "trim", it matches `CustomFunctions` -> `trim` and
validates against your custom rules.
* If `call` is "unknownFunc":
* If `GenericFunction` is NOT included, validation FAILS immediately (
strict mode).
* If `GenericFunction` IS included, it matches the generic fallback and
PASSES (loose mode).

This strict-by-default approach ensures typos are caught early, while the
modular structure makes it easy to add new capabilities.
5 changes: 4 additions & 1 deletion specification/v0_9/json/common_types.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@
"default": "boolean"
}
},
"required": ["call"]
"required": ["call"],
"oneOf": [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we just leave this oneOf out of common_types.json, then step 2 in the documentation is entirely unnecessary. Couldn't you instead add a required block at the end of the list of functions in the catalog that requires at least one of the the functions, so you don't need the separate Functions definition? I'd like to find a way where the catalog contains all of the validation needed, and we don't need to customize the common types for each client.

{ "$ref": "catalog.json#/$defs/anyFunction" }
]
},
"LogicExpression": {
"type": "object",
Expand Down
Loading