You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Base branch:claude/implement-get-actor-run-MUTXI (or master once merged).
Sub-issue of #582. Behavior change. Depends on #762 (refactor) and #763 (cancel fix).
Context
After #762 lands the shared helpers and #763 fixes the cancel-AbortSignal chain, this PR delivers #582:
call-actor (default + apps + apps-widget) returns the new uniform shape {runId, actorName, status, startedAt, storages, hint} — no input echo, no inline preview.
Defaultcall-actor (src/tools/default/call_actor.ts) flips from sync-with-preview to start-and-return. Apps variants already start-and-return — they only need the new response shape.
In MCP task mode (server-internal mcpTaskExecution flag), call-actor waits for completion before returning. Task stays working, SDK serves final result via tasks/result.
get-actor-run and get-actor-run-widget gain waitSecs (0–60 s, default 10). Server-side bounded wait via apifyClient.run(runId).waitForFinish({ waitSecs }).
async and previewOutput removed from callActorArgs.
Inline 5-item dataset preview removed from fetchActorRunData.
Widget React: pass waitSecs: 0; once SUCCEEDED, fetch preview separately via get-actor-output.
Non-goals
Direct actor tools (RAG Web Browser et al.) keep their current sync-with-preview behavior and callActorOutputSchema.actor_tools_factory.ts and callActorGetDataset are out of scope. Tracked as feat: Async call-actor with uniform response + waitSecs on get-actor-run #582 follow-up. Rationale: direct actor tools are pre-configured ergonomic shortcuts — agents invoke RWB expecting data, not metadata.
actorName, finishedAt, stats are optional. actorName is populated whenever the actor lookup succeeds (always for call-actor; best-effort for get-actor-run).
callActorArgs (src/tools/core/call_actor_common.ts) — drops async and previewOutput
exportconstcallActorArgs=z.object({actor: z.string().describe(/* unchanged */),input: z.object({}).passthrough().describe('The input JSON to pass to the Actor. Required.'),callOptions: z.object({memory: z.number().min(128).max(32768).optional().describe(/* unchanged */),timeout: z.number().min(0).optional().describe(/* unchanged */),}).optional(),});
exportconstgetActorRunArgs=z.object({runId: z.string().min(1).describe('The ID of the Actor run.'),waitSecs: z.number().int().min(0).max(60).default(10).describe('Maximum seconds to wait for the run to finish (0–60, default 10). The server polls and '+'returns immediately when a terminal state is reached — waitSecs is a ceiling, not a fixed delay. '+'If still active after this time, returns current status — call again to continue waiting. '+'Use 0 for an instant status check without waiting.'),});
exportfunctiongetRunStatusHint(status: string): string{switch(status){case'READY':
case'RUNNING':
return'Use `get-actor-run` to wait for the Actor run to finish.';case'SUCCEEDED':
return'Use `get-actor-output` with the `datasetId` from `storages` to retrieve Actor run results.';case'FAILED':
case'ABORTING':
case'ABORTED':
case'TIMING-OUT':
case'TIMED-OUT':
return'Actor run failed. Use `get-actor-log` to inspect what went wrong.';default:
return'Use `get-actor-run` to check status.';}}
Scope
mcpTaskExecution flag — task path only
src/mcp/server.ts:executeToolAndUpdateTask: pass mcpTaskExecution: true in the tool.call({...}) argument bag.
The non-task site stays unchanged — flag absent / false.
Update buildCallActorDescription to drop the alwaysAsync: false branch (and the async paragraph at the bottom). Description becomes one shape: always async.
src/tools/apps/call_actor_widget.ts: add mcpTaskExecution branch. Keep widget _meta. Switch to actorRunOutputSchema.
get-actor-run handlers
src/tools/core/get_actor_run_common.ts:
Add waitSecs to getActorRunArgs (locked schema above).
In fetchActorRunData: switch to client.run(runId).waitForFinish({ waitSecs }) when waitSecs > 0; client.run(runId).get() when waitSecs === 0.
Drop the inline preview block (if (run.status === 'SUCCEEDED' && run.defaultDatasetId) { listItems({limit:5}) ... } and the dataset field on structuredContent).
Replace structuredContent shape with buildActorRunStructuredContent.
Switch outputSchema to actorRunOutputSchema.
Update buildGetActorRunSuccessResponse: widget branch loses preview text, drops dataset reference.
Default call-actor no longer blocks; no inline preview; no input echo
Existing clients see only run metadata; must call get-actor-output
async and previewOutput removed from input schema
Clients passing them get INVALID_INPUT
Both get-actor-run variants: no inline preview
Widget + clients must call get-actor-output
get-actor-run waits up to 10 s by default
Pass waitSecs: 0 for instant lookup
Coordinate with apify-mcp-server-internal before merge: confirm no test or caller relies on the old async/previewOutput params or inline preview shape.
Acceptance
npm run type-check, npm run lint, npm run test:unit clean
mcpc end-to-end: call-actor → get-actor-run(waitSecs:30) → get-actor-output succeeds for apify/python-example
Task-aware client: call-actor task stays working; tasks/result returns final run metadata
Widget polls with waitSecs: 0, fetches preview via get-actor-output, cancellation aborts the Apify run
apify-mcp-server-internal smoke test still passes (manual, post-merge)
Independence
Depends on #762 and #763. Stack on their branches or rebase after merge.
Base branch:
claude/implement-get-actor-run-MUTXI(or master once merged).Sub-issue of #582. Behavior change. Depends on #762 (refactor) and #763 (cancel fix).
Context
After #762 lands the shared helpers and #763 fixes the cancel-AbortSignal chain, this PR delivers #582:
call-actor(default + apps + apps-widget) returns the new uniform shape{runId, actorName, status, startedAt, storages, hint}— noinputecho, no inline preview.call-actor(src/tools/default/call_actor.ts) flips from sync-with-preview to start-and-return. Apps variants already start-and-return — they only need the new response shape.mcpTaskExecutionflag),call-actorwaits for completion before returning. Task staysworking, SDK serves final result viatasks/result.get-actor-runandget-actor-run-widgetgainwaitSecs(0–60 s, default 10). Server-side bounded wait viaapifyClient.run(runId).waitForFinish({ waitSecs }).asyncandpreviewOutputremoved fromcallActorArgs.fetchActorRunData.waitSecs: 0; onceSUCCEEDED, fetch preview separately viaget-actor-output.Non-goals
callActorOutputSchema.actor_tools_factory.tsandcallActorGetDatasetare out of scope. Tracked as feat: Async call-actor with uniform response + waitSecs on get-actor-run #582 follow-up. Rationale: direct actor tools are pre-configured ergonomic shortcuts — agents invoke RWB expecting data, not metadata.get-actor-outputacceptingrunIdas alternative todatasetId— feat: Async call-actor with uniform response + waitSecs on get-actor-run #582 follow-up.Schema (locked)
Final shapes that the implementation must match exactly.
actorRunOutputSchema(new, insrc/tools/structured_output_schemas.ts)actorName,finishedAt,statsare optional.actorNameis populated whenever the actor lookup succeeds (always forcall-actor; best-effort forget-actor-run).callActorArgs(src/tools/core/call_actor_common.ts) — dropsasyncandpreviewOutputgetActorRunArgs(src/tools/core/get_actor_run_common.ts) — addswaitSecsgetRunStatusHint(src/tools/core/call_actor_common.ts)Scope
mcpTaskExecutionflag — task path onlysrc/mcp/server.ts:executeToolAndUpdateTask: passmcpTaskExecution: truein thetool.call({...})argument bag.call-actorhandlerssrc/tools/core/call_actor_common.ts:asyncandpreviewOutputfromcallActorArgs.inputecho frombuildStartAsyncResponse. Replace itsstructuredContentwithbuildActorRunStructuredContent(from refactor: Extract shared run helpers and run output schema #762).buildCallActorDescriptionto drop thealwaysAsync: falsebranch (and theasyncparagraph at the bottom). Description becomes one shape: always async.src/tools/default/call_actor.ts:callActorGetDatasetcall entirely.apifyClient.actor(name).start(input, callOptions).toolArgs.mcpTaskExecution:waitForRunWithAbortthen return finalbuildActorRunStructuredContent.buildActorRunStructuredContentimmediately.outputSchematoactorRunOutputSchema.src/tools/apps/call_actor.ts: addmcpTaskExecutionbranch (otherwise unchanged — already start-and-return). Switch toactorRunOutputSchema.src/tools/apps/call_actor_widget.ts: addmcpTaskExecutionbranch. Keep widget_meta. Switch toactorRunOutputSchema.get-actor-runhandlerssrc/tools/core/get_actor_run_common.ts:waitSecstogetActorRunArgs(locked schema above).fetchActorRunData: switch toclient.run(runId).waitForFinish({ waitSecs })whenwaitSecs > 0;client.run(runId).get()whenwaitSecs === 0.if (run.status === 'SUCCEEDED' && run.defaultDatasetId) { listItems({limit:5}) ... }and thedatasetfield onstructuredContent).structuredContentshape withbuildActorRunStructuredContent.outputSchematoactorRunOutputSchema.buildGetActorRunSuccessResponse: widget branch loses preview text, dropsdatasetreference.src/tools/default/get_actor_run.ts,src/tools/apps/get_actor_run_widget.ts: forwardparsed.waitSecs. Widget Zod schema gainswaitSecs.Widget React (
src/web/src/pages/ActorRun/ActorRun.tsx)waitSecs: 0on everyget-actor-run-widgetcall.status === 'SUCCEEDED', fetch preview viaget-actor-output(datasetId, limit 5). Render the same table.dataset.previewItemsdependency on the widget response.Server instructions
src/utils/server-instructions/index.ts(and any per-mode strings): align the call-actor paragraph with the start → wait → fetch flow.Plan
mcpTaskExecution: trueonly insideexecuteToolAndUpdateTaskbuildActorRunStructuredContentin all three call-actor variantsasync/previewOutputfromcallActorArgsand descriptioncall-actor: remove sync-preview path; add task-mode waitcall-actor: add task-mode waitwaitSecson bothget-actor-runvariantsfetchActorRunDatawaitSecs: 0+ separateget-actor-outputfetchwaitSecs: 0instant;waitSecs: 5returns within ~5 spreviewOutput/asynccases; cover task mode + cancellation (relies on fix: tasks/cancel must abort the running tool handler #763); coverwaitSecsFiles touched
src/mcp/server.tssrc/tools/default/call_actor.tssrc/tools/apps/call_actor.tssrc/tools/apps/call_actor_widget.tssrc/tools/core/call_actor_common.tssrc/tools/core/get_actor_run_common.tssrc/tools/default/get_actor_run.tssrc/tools/apps/get_actor_run_widget.tssrc/utils/server-instructions/index.tssrc/web/src/pages/ActorRun/ActorRun.tsxtests/unit/...,tests/integration/suite.tsREADME.mdBreaking changes
call-actorno longer blocks; no inline preview; noinputechoget-actor-outputasyncandpreviewOutputremoved from input schemaINVALID_INPUTget-actor-runvariants: no inline previewget-actor-outputget-actor-runwaits up to 10 s by defaultwaitSecs: 0for instant lookupCoordinate with
apify-mcp-server-internalbefore merge: confirm no test or caller relies on the oldasync/previewOutputparams or inline preview shape.Acceptance
npm run type-check,npm run lint,npm run test:unitcleancall-actor→get-actor-run(waitSecs:30)→get-actor-outputsucceeds forapify/python-examplecall-actortask staysworking;tasks/resultreturns final run metadatawaitSecs: 0, fetches preview viaget-actor-output, cancellation aborts the Apify runapify-mcp-server-internalsmoke test still passes (manual, post-merge)Independence
Depends on #762 and #763. Stack on their branches or rebase after merge.
Estimate
~5 h.