feat: Run/standby mode decision table for Actor tool loading - #1278
Draft
jirispilka wants to merge 1 commit into
Draft
feat: Run/standby mode decision table for Actor tool loading#1278jirispilka wants to merge 1 commit into
jirispilka wants to merge 1 commit into
Conversation
jirispilka
force-pushed
the
claude/actor-tool-mode-table-vbiyfw
branch
from
August 20, 2026 16:36
fb857c5 to
3b2a2d7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this solves
Closes #1208.
There was no single rule for how an Actor becomes a tool. Run mode, standby mode and
webServerMcpPathwere each read in a different place, and two of the resulting cells were wrong.Now one function,
resolveActorToolType, decides, and tool loading,call-actorrouting andfetch-actor-detailsall read it — so they can never disagree again.Before → after, per cell
webServerMcpPathCell 2 — run-only Actor with a leftover
webServerMcpPath(the MCP-URL resolution checked thepath but never
actorStandby.isEnabled):Cell 5 — standby-only Actor, no MCP server, empty input schema (nothing to run, nothing to
proxy — the old run tool couldn't do anything, and the two
call-actorshapes invented twodifferent reasons):
The message is built from the platform-canonical Actor name on both paths, so addressing the Actor
by ID yields the same text. Same for the standby-under-payment-provider rejection, which previously
echoed the caller's raw identifier (including a
:toolNamesuffix) into the message.Observability
log.softFailwithactorLoadErrorKind,and the user-error responses carry
failureDetail: <kind>— the rejections are queryable in Mezmoinstead of invisible.
STANDBY_PAYMENT_NOT_SUPPORTEDresponses move fromFAILED/INTERNAL_ERROR+ error log toSOFT_FAIL/INVALID_INPUT+ softFail. It's a clientmistake, not a server fault — but existing queries keyed on the old category will stop matching.
@apify/logroutes anything below ERROR to stdout, which isthe JSON-RPC channel, so these lines are telemetry-only under stdio.
Impact on
apify-mcp-server-internalA standby-only Actor with an empty input schema now produces no tool at all instead of an
unusable run tool. Bulk session-boot loading still discards per-Actor load errors, so such an Actor
silently disappears from
tools/list(with a server-side softFail trace); the error text reaches auser only through
call-actor. The newActorLoadErrorkind is additive; internal imports none ofthe touched symbols.
Known and accepted
handleMcpToolCallparameter collapse (isActorMcpServer+mcpServerUrl→ one resolveddiscriminated union) rides along with the feature, against "refactoring is a separate PR". The
feature needs the caller to distinguish "run tool" from "unsupported cell"; a separate landing
would have meant a throwaway tri-state in between.
STANDBY_PAYMENT_NOT_SUPPORTEDarm inbuildCallActorErrorResponseis currently unreachablein production (the pre-flight guard intercepts first). Kept as a tested defensive fallback.
fetch-actor-detailsstill answers "not an MCP server" for the unsupported cell — only the twocall-actorshapes were in scope for the new message.Verification
src/.tools/listand bothcall-actorshapes, plus ID-vs-name canonicalization and message distinctness.
mcpcprobe:apify/normal-mode-test-actor(standby-disabled) loads as a run tool and ranvia bare
call-actor;apify/example-mcp-serverderived the correct standby URL (handshakeblocked only by this sandbox's egress proxy).
(
acme--standby-mcp--add). Full suite green: 1465 unit tests, type-check, lint, format,check:agents.
Follow-ups
apify/web-fetchas a default tool) is unblocked by this PR.AI-assisted: written with Claude Code under a human-gated design and review pipeline, plus an
iterative staff-review loop over the final diff.