Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/endpoints/scenarios.tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,39 @@ export const tools: MakeTool[] = [
return await make.scenarios.run(scenarioId, data, { responsive, callbackUrl });
},
},
{
name: 'scenarios_replay',
title: 'Replay scenario execution',
description:
"Replay a past execution of a scenario, re-running it with the trigger data the original execution received. Get candidate execution IDs from executions_list. Only executions whose input data is still stored can be replayed — 'Execution is not replayable' means that execution's data has expired or was never stored, so try a MORE RECENT execution instead of retrying the same one. Only the first ID in executionIds is replayed. The scenario must be ACTIVE. A replay starts a real execution and consumes operations exactly like scenarios_run; it returns the executionId of the NEW execution, which you can inspect with executions_get-detail.",
category: 'scenarios',
scope: 'scenarios:run',
scopeId: 'scenarioId',
identifier: 'scenarioId',
resourceId: 'scenarioId',
annotations: {
readOnlyHint: false,
destructiveHint: true,
openWorldHint: true,
},
inputSchema: {
type: 'object',
properties: {
scenarioId: { type: 'number', description: 'The ID of the scenario the execution belongs to' },
executionIds: {
type: 'array',
items: { type: 'string' },
description:
'Execution IDs to replay, as returned by executions_list. Currently only the first one is replayed.',
},
Comment on lines +483 to +488
},
required: ['scenarioId', 'executionIds'],
},
examples: [{ scenarioId: 925, executionIds: ['509f0457d2804ba7b115faf1637beea6'] }],
execute: async (make: Make, args: { scenarioId: number; executionIds: string[] }) => {
return await make.scenarios.replay(args.scenarioId, args.executionIds);
},
},
{
name: 'scenarios_interface',
title: 'Get scenario interface',
Expand Down
26 changes: 26 additions & 0 deletions src/endpoints/scenarios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,14 @@ export type RunScenarioOptions = {
callbackUrl?: string;
};

/**
* Response format for replaying a scenario execution.
*/
export type ReplayScenarioResponse = {
/** ID of the new execution created by the replay (not the ID of the execution being replayed) */
executionId: string;
};

/**
* Response format for activating a scenario.
*/
Expand Down Expand Up @@ -522,6 +530,24 @@ export class Scenarios {
});
}

/**
* Replay a past execution of a scenario, re-running it with the original trigger data.
*
* Only executions whose input artifacts are still stored can be replayed; the API answers
* `422 Execution is not replayable` for the rest, and `404` for an unknown execution ID.
* @param scenarioId The scenario ID the execution belongs to
* @param executionIds Execution IDs to replay. Currently only the first one is replayed.
* @returns Promise with the ID of the new execution created by the replay
*/
async replay(scenarioId: number, executionIds: string[]): Promise<ReplayScenarioResponse> {
return await this.#fetch<ReplayScenarioResponse>(`/scenarios/${scenarioId}/replay`, {
method: 'POST',
body: {
executionIds,
},
});
}

/**
* Get the interface for a scenario.
* @param scenarioId The scenario ID to get the interface for
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export type {
UpdateScenarioInterfaceBody,
RunScenarioResponse,
RunScenarioOptions,
ReplayScenarioResponse,
Scheduling,
} from './endpoints/scenarios.js';
export type {
Expand Down
3 changes: 3 additions & 0 deletions test/mocks/scenarios/replay.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"executionId": "3f2a91c6d8b04e57ac1d5e9074bb2f83"
}
13 changes: 13 additions & 0 deletions test/scenarios.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as scenariosMock from './mocks/scenarios/list.json';
import * as scenarioInterfaceMock from './mocks/scenarios/interface.json';
import * as scenarioUpdateInterfaceMock from './mocks/scenarios/update-interface.json';
import * as scenarioRunMock from './mocks/scenarios/run.json';
import * as scenarioReplayMock from './mocks/scenarios/replay.json';
import * as scenarioActivateMock from './mocks/scenarios/activate.json';
import * as scenarioCreateMock from './mocks/scenarios/create.json';
import * as scenarioGetMock from './mocks/scenarios/get.json';
Expand Down Expand Up @@ -135,6 +136,18 @@ describe('Endpoints: Scenarios', () => {
expect(result).toStrictEqual(scenarioRunMock);
});

it('Should replay scenario execution', async () => {
const executionIds = ['509f0457d2804ba7b115faf1637beea6'];

mockFetch('POST https://make.local/api/v2/scenarios/18/replay', scenarioReplayMock, req => {
expect(req.body).toStrictEqual({ executionIds });
expect(req.headers.get('content-type')).toBe('application/json');
});

const result = await make.scenarios.replay(18, executionIds);
expect(result).toStrictEqual(scenarioReplayMock);
});

it('Should activate scenario', async () => {
mockFetch('POST https://make.local/api/v2/scenarios/5/start', scenarioActivateMock, req => {
expect(req.body).toBe('');
Expand Down