ambleloft

Turn messages into business actions

Messages can be actionable: execute after host confirmation and report the actual business outcome.

PRACTICAL GUIDE

Outcome: Connect a message action to an operation and report the result.

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

01Start with the complete sample

message-actions includes a separate local service, publication, invocation records and query-based reconciliation. Start action-service and configure its address as described in the README. A service accepting a task does not mean it has completed.

Open the complete runnable sample

02Declare and bind an Operation

At most two actions are supported. commandId must name a same-extension operation exposed to page, not an openHome command from contributes.commands. arguments must satisfy the operation inputSchema; writes use effect: write.

LocalMessageInput · example fragment
actions: [{
  id: 'submit',
  label: 'Submit task',
  commandId: context.extensionId + '.actionRun',
  arguments: { eventKey: 'task:42', mode: 'normal' }
}]

03Use host-issued invocation records

Find the invocation record using invocation.message.invocationId and use record.id as the remote idempotency key. The host resolves the stored action and arguments, rechecking trust, version, grants, message state and confirmation.

Inside the actionRun backend handler
const id = invocation.message?.invocationId;
if (!id) throw Object.assign(new Error('Message context required'), { code: 'FORBIDDEN' });
const record = (await messages.listActionInvocations()).find(r => r.id === id);
if (!record) throw Object.assign(new Error('Record not found'), { code: 'NOT_FOUND' });

04Report accepted / completed / unknown

Report accepted only after the service accepts the task, saving remoteTaskId; report completed after actual completion. Returning from the handler does not mark completion. reportId identifies a report: the same ID and content can be retried, but this does not authorize replaying a business write.

After the business service confirms acceptance
await messages.reportActionResult({
  invocationId: record.id,
  reportId: 'initial-accepted',
  expectedRevision: record.revision,
  outcome: 'accepted',
  remoteTaskId: remote.id
});

05Timeouts, restarts and resolving messages

Query uncertain outcomes without automatically re-executing. On restart, prepared records can become notExecuted and dispatching records become unknown. completed does not automatically resolve a message: send messageUpdate with the message own expectedRevision. Conflicts in either side fail the atomic update.

Read the message action API

Check the result and troubleshoot

Connect a message action to an operation and report the result.

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