Блог • App Intents

Как агент iOS 27 вызывает стороннее приложение: проверка JSON App Intent до API

Когда система вызывает стороннее приложение, вход — объявленный вами AppIntent. После того как параметры попали в perform() и до API, запишите их как JSON. Если тип, enum или обязательный ключ не совпали, верните запись об отказе и остановите вызов внутри приложения.

Как один запрос доходит до API — в статье JSON-путь App Action. Станет ли Siri агентом — в статье Станет ли Siri AI агентом. Здесь только сторона приложения: какие параметры объявить, что останавливает схема и какой JSON вернуть при отказе.

Сначала это: Вызов, дошедший до приложения, ещё не значит, что параметры готовы. Дальше: объявленный контракт, одна схема, три отказа, верная форма, которую всё равно надо остановить, и как отказ возвращается.

Сначала объявить контракт параметров

Вход стороннего приложения — это AppIntent. Вы задаёте заголовок и реализуете perform(). Система находит действие, потому что вы его объявили. Объявление не доказывает, что эти параметры можно отправлять в API.

Каждый параметр помечайте @Parameter. См. Добавление параметров в App Intent. Этот пример принимает только три вещи: id товара, количество и способ получения. Имена, пояснения и лишние ключи модели в контракт не входят.

  1. 1
    Зафиксировать имя Intent

    Поле intent в JSON кандидата может быть только PlaceOrderIntent. Другое имя значит, что вызов попал не в то действие.

  2. 2
    Перечислить три параметра

    itemId — строка, quantity — целое, fulfillment — только pickup или delivery. Если нет любого из них, кандидат неполон.

  3. 3
    Проверять в начале perform()

    Если проверка не прошла, верните запись об отказе ниже. К API переходите только после успеха, разрешения id и количества не меньше 1.

Те же поля записать схемой

Кандидат и схема ниже — ваш контракт, не сетевой формат Apple. JSON Schema в JSONNote проверяет типы, enum и обязательные ключи. Правило «количество не меньше 1, id должен существовать» эта схема не выражает. Это решает приложение.

Кандидат, который может идти к следующей проверке. fulfillment — pickup или delivery.
{
  "intent": "PlaceOrderIntent",
  "parameters": {
    "itemId": "sku_42",
    "quantity": 1,
    "fulfillment": "pickup"
  }
}
Кандидат — в первое поле, эту схему — во второе. действовать переключите на Проверьте с помощью Schema.
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["intent", "parameters"],
  "properties": {
    "intent": { "enum": ["PlaceOrderIntent"] },
    "parameters": {
      "type": "object",
      "required": ["itemId", "quantity", "fulfillment"],
      "properties": {
        "itemId": { "type": "string" },
        "quantity": { "type": "integer" },
        "fulfillment": { "enum": ["pickup", "delivery"] }
      }
    }
  }
}

Как типы параметров совпадают — в статье поля действия приложения и JSON Schema. Эту таблицу статья не повторяет. Здесь только то, что приложение возвращает, когда проверка не прошла.

Три кандидата, которые не проходят

Что изменили в кандидатеПочему не проходит
fulfillment равен shipЭто не pickup и не delivery.
quantity — строка 1Контракт требует целое число.
itemId удалёнНет обязательного ключа, кандидат неполон.

Поставьте quantity равным 0: тип остаётся целым, схема проходит. Прохождение — ещё не заказ. Количество 0 приложение должно отклонить.

Верная форма всё равно может остановить

Запись об отказе, когда количество меньше 1. dialog — фраза, которую видит человек.
{
  "intent": "PlaceOrderIntent",
  "status": "rejected",
  "reason": "invalid_parameter",
  "field": "quantity",
  "dialog": "Quantity must be at least 1."
}

Непустой itemId тоже проходит схему. Затем разрешите этот id в своих данных. Если не разрешился, запишите ещё один rejected с field равным itemId. Не выдумывайте id из названия товара и не вызывайте API.

Как отказ возвращается

Если нет обязательного значения, спросите ещё раз через requestValue у этого параметра. Не вызывайте API с пустым значением. Если значение недопустимо, остановите perform() и используйте IntentDialog, чтобы написать фразу, которую человек может прочитать. JSON выше — запись, которую вы храните для этого решения.

Случайstatus в записиAPI
нет fulfillmentneeds_valueСпросить ещё раз, API не вызывать
fulfillment равен shiprejectedСообщить, что допустимы только pickup и delivery
quantity равен 0rejectedОстановить, хотя форма верна
itemId не разрешаетсяrejectedНе подменять id названием товара

needs_value значит, что ещё нужно спросить. rejected значит, что этот кандидат нельзя выполнять. Оба не доходят до API. Человек видит фразу dialog. В журнале остаётся весь JSON, чтобы позже было видно, какое поле остановило вызов.

Чем эта статья отличается от других

Статья о пути запросаСтатья о конверте обменаЭта статья
ОтвечаетКак фраза доходит до APIКакой JSON лежит между значением модели и параметрамиКак приложение объявляет, проверяет и возвращает отказ
Здесь не ищитеЕщё один проход от речи до APIДва объекта content и parametersПодмену id сущности названием товара

Остановить вызов в JSONNote

  1. 1
    Выбрать нужную операцию

    Откройте JSON Schema. Переключите действовать на Проверьте с помощью Schema. Кандидат — в первое поле, схему выше — во второе. intent может быть только PlaceOrderIntent. fulfillment — только pickup или delivery. quantity — целое.

  2. 2
    Прогнать три плохих документа

    Поставьте fulfillment равным ship, quantity — строке 1, или удалите itemId. Все три не проходят. quantity 0 проходит. После этого всё равно запишите rejected и не вызывайте API.

  3. 3
    Сравнить 1 и 0

    Откройте JSON Сравнить Diff. В первое поле — parameters с quantity 1, во второе — тот же объект с quantity 0. Разница в этом числе. 0 по-прежнему проходит схему. API останавливает запись об отказе, а не эта проверка формы.

Вопросы

Если система уже передала приложению параметры, их всё равно проверять?

Да. Система передала вызов, а не уже проверенный запрос API. В начале perform() смотрите этот JSON. Если он не прошёл, не продолжайте.

Можно ли вызывать API, как только схема прошла?

Ещё нет. Эта схема смотрит только тип, enum и обязательные ключи. quantity 0 проходит. Строковый itemId тоже проходит. Вызывайте API только когда количество не меньше 1 и id разрешается.

Если параметра нет, вернуть ошибку или спросить ещё раз?

Спросите ещё раз. status равен needs_value, а requestValue просит это значение у человека. Не вызывайте API, пока нет допустимого значения. Если значение пришло и оно недопустимо, запишите rejected.

Это та же статья, что про JSON-путь одного запроса?

Нет. Та статья ведёт один запрос от фразы до API. Эта остаётся внутри приложения: контракт параметров, схема и JSON, который возвращают при отказе. API выполняется только если не записаны ни rejected, ни needs_value.

Запись об отказе — это формат ответа Apple?

Нет. Apple передаёт результат системе и человеку через requestValue и IntentDialog. Этот JSON — ваш собственный журнал: status, reason, field, dialog. Храните его, чтобы в JSONNote проверить, почему API не вызывался.

Итог

Когда вызывают стороннее приложение, сначала есть контракт параметров, затем JSON, которому разрешено не пройти. Запись об отказе останавливает вызов до API и сохраняет одну читаемую фразу dialog.

Решение: сначала объявить параметры Intent; схема останавливает неверные типы, enum и пропущенные обязательные ключи; needs_value, если значения нет; rejected, если значение недопустимо; оба не вызывают API; количество меньше 1 или отсутствующий id останавливают вызов и при верной форме.

Дальше: прогоните параметры кандидата через схему, затем решите, продолжать вызов или вернуть отказ.

Назад в блог