ambleloft

Multi-step forms and recovery

Build on declarative business forms to save business drafts, submit applications and reconcile uncertain results through extension operations. Multi-step navigation itself requires no business server.

PRACTICAL GUIDE

Outcome: Run the multi-step form sample and verify submission, recovery and failure paths.

Before you begin: Prepare the files and tools specified on this page. The previous page in the learning path is not automatically a dependency.

On this page

01Run the complete business template

First complete local package setup in the first-extension guide. Run from extension-work with AMBLELOFT_PACKS still set. The CLI does not install dependencies.

Code example
npx --no-install amble-extension init expense-demo --name expense-demo --template expense
cd expense-demo
npm install --save-dev "$AMBLELOFT_PACKS/ambleloft-extension-sdk-0.1.0-alpha.9.tgz" "$AMBLELOFT_PACKS/ambleloft-extension-core-0.1.0-alpha.9.tgz" "$AMBLELOFT_PACKS/ambleloft-extension-cli-0.1.0-alpha.9.tgz"
npm run build
npm run validate
npm run pack
Open the complete runnable sample

02Complete template: itinerary → expenses → confirmation

This is the existing expense-workflow template. Its operation IDs belong to samples.expense-workflow. When adapting it, update both manifest and template IDs. next executes when advancing a step; submit executes at final submission.

expense-workflow/skills/expense/forms/travel.yaml
version: 1
id: travel
title: 财务报销助手
description: 本机模拟报销。修改行程会生成新草稿;返回上一步不会撤销业务记录。
steps:
  - id: itinerary
    title: 行程
    fields:
      - name: region
        type: select
        label: 出差地区
        required: true
        options:
          - {label: 上海, value: shanghai}
          - {label: 北京, value: beijing}
      - {name: date, type: date, label: 出差日期, required: true}
    next:
      kind: operation
      label: 保存行程并继续
      operation: samples.expense-workflow.saveDraft
      input:
        region: {from: steps.itinerary.region}
        date: {from: steps.itinerary.date}
      recovery: {operation: samples.expense-workflow.lookupDraft}
  - id: expenses
    title: 费用
    fields:
      - {name: amount, type: money, label: 金额, currency: CNY, scale: 2, minimum: '0.01', maximum: '1000000.00', required: true}
      - {name: remark, type: textarea, label: 说明, maxLength: 2000, required: true}
  - id: confirmation
    title: 确认
    fields:
      - {name: confirmed, type: checkbox, label: 我已核对报销信息, required: true}
submit:
  kind: operation
  label: 提交报销
  operation: samples.expense-workflow.submitExpense
  input:
    draftId: {from: results.itinerary.draftId}
    amount: {from: steps.expenses.amount}
    remark: {from: steps.expenses.remark}
    confirmed: {from: steps.confirmation.confirmed}
  recovery: {operation: samples.expense-workflow.lookupExpense}

03How input bindings resolve

The host resolves bindings. YAML cannot execute JavaScript or construct API URLs. The business operation inputSchema and outputSchema remain the contract.

Field / APIContract
steps.<step>.<field>Read a field from a step, e.g. steps.expenses.amount.
results.<step>.<key>Read a completed step operation output, such as draftId.
context.projectIdBind the current project; project-scoped operations must match invocation context.
{ value: ... }A literal string, number or boolean.

04Use submissionId for writes

Read host-issued submissionId, flowInstanceId, stepId, templateDigest and conversationId from invocation.form. Use submissionId as the business idempotency key. requestId is not equivalent, and input.form is not trusted context. Expose form write operations to page so the host can invoke them after confirmation.

05Recovery return contract

recovery names a read operation in the same extension exposed to page. Read input.submissionId, not invocation.form. succeeded.result contains the original business output and is validated against its outputSchema. A timeout or missing record is not proof of notExecuted. Return it only with an explicit execution barrier; query unknown outcomes without replaying the write.

Recovery protocol · signature
type FormRecoveryResult<T> =
  | { status: 'succeeded'; result: T }
  | { status: 'notExecuted' }
  | { status: 'unknown' };

06Test the failure paths

Check required fields and money limits, cancelled confirmation, disconnected service, a successful write with a lost response, and query-based recovery. Going back does not undo saved drafts. Changed templates do not migrate old instances. There is no public forms_resume API.

Read the YAML field reference

Check the result and troubleshoot

Run the multi-step form sample and verify submission, recovery and failure paths.

Check actual results using this page’s verification steps. For business integrations, inspect UI submission, tool receipts and server records separately.

Open the error reference →
SDK / CLI 0.1.0-alpha.9 · Contract baseline Compatibility and preview notes · Sample source