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.
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.
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 pack02Complete 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.
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 / API | Contract |
|---|---|
| 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.projectId | Bind 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.
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 referenceCheck 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 →