Turn messages into business actions
Messages can be actionable: execute after host confirmation and report the actual business outcome.
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 sample02Declare 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.
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.
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.
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 APICheck 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 →