Skip to content

fix: Keep Actor run retries conditional on user intent - #1564

Merged
jirispilka merged 3 commits into
masterfrom
fix/run-next-step-no-rerun
Oct 14, 2026
Merged

jirispilka merged 3 commits into
masterfrom
fix/run-next-step-no-rerun

Conversation

@jirispilka

@jirispilka jirispilka commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Run results used to tell the model to start another Actor run after a failed, aborted, or empty run. That could trigger a retry the user did not want. Aborted runs may also have partial dataset items worth checking.

Closes #1559
Closes apify/ai-team#255

What changed

  • For SUCCEEDED runs with no dataset items and for FAILED runs, nextStep starts with diagnosis. It mentions retrying only if the user wants another attempt.
  • For ABORTED runs, nextStep points out that earlier items remain in the default dataset and leaves another run to the user.
  • The same text reaches get-actor-run, abort-actor-run, call-actor, and direct Actor tools. It names no additional tool.

Validation

  • Updated response tests failed before the wording change and pass afterward.
  • pnpm run type-check, pnpm run lint, pnpm run test:unit (2631 passed, 1 skipped), pnpm run format, and pnpm run check:agents pass.

AI assistance: Claude Code prepared the original change and mcpc probe. Codex revised the wording, tests, and this description.

The FAILED, ABORTED and SUCCEEDED-without-items nextStep in run
responses no longer ask for a new run. The ABORTED nextStep now says
that items written before the abort stay in the run's default dataset.

Closes #1559
Closes apify/ai-team#255

Claude-Session: https://claude.ai/code/session_0149C4bPjve1UHWcxTtBsPXC
@jirispilka jirispilka changed the title fix: Stop asking the model to re-run the Actor in run results fix: Keep Actor run retries conditional on user intent Oct 14, 2026
@jirispilka
jirispilka marked this pull request as ready for review October 14, 2026 07:32
@jirispilka jirispilka added the t-ai Issues owned by the AI team. label Oct 14, 2026
@apify-service-account apify-service-account added the tested Temporary label used only programatically for some analytics. label Oct 14, 2026
jirispilka added a commit that referenced this pull request Oct 14, 2026
…#1565)

## Why

Closes #1561

Review page with before/after examples for this PR and the five related
ones (#1563, #1564, #1566–#1568):
https://claude.ai/artifact/WDRj1nwPnMTP9ktGyg3z3i

Tool errors with an HTTP status that has no specific hint (400, 404,
405, 409, …) ended with "Verify the tool name and input parameters.",
though the tool name was right and the input valid. A missing run, for
example, read as if the call itself was wrong.

## What changed

The generic hint is now appended only when the error has no HTTP status.
With a status, the 401, 403, 429 and 5xx hints stay; any other status
adds nothing, since the text already carries the API's message and error
type. The run-limit and cannot-publish branches are unchanged.

`abort-actor-run` with a nonexistent `runId` (404):

```
Before: Error calling tool "abort-actor-run": Actor run was not found (API error type: record-not-found). Verify the tool name and input parameters.
Now:    Error calling tool "abort-actor-run": Actor run was not found (API error type: record-not-found).
```

An error without a status (a network failure, a plain `Error`) still
ends with "Verify the tool name and input parameters.". This is a
tool-text change to the error text every tool returns; no eval case
references the removed hint.

## Notes for reviewers (human-written)

## Proof it works

mcpc with the Claude connector tool set, this branch against a build
with master's `src/utils/mcp.ts`:

| Call | master | this branch |
|---|---|---|
| `abort-actor-run runId:="doesNotExist123"` | `… Actor run was not
found (API error type: record-not-found). Verify the tool name and input
parameters.` | `… Actor run was not found (API error type:
record-not-found).` |
| `get-actor-run runId:="doesNotExist123"` | `Run with ID
'doesNotExist123' not found.` | unchanged (the tool words its own
not-found error) |
| `get-key-value-store-record keyValueStoreId:="doesNotExist123"
recordKey:="INPUT"` | `Key-value store 'doesNotExist123' not found.` |
unchanged (own error) |

Unit tests (the 400 and 404 cases failing before the fix):
`getToolCallErrorUserText()` for 400 and 404 (no hint), 401, 403, 429
and 500 (hint kept) and an error without a status (generic hint kept),
and a `tools/call` of a tool that throws a 404.

Implemented with Claude Code: code, tests, mcpc probe and this
description. Reviewed by a separate Claude Code review pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_0149C4bPjve1UHWcxTtBsPXC

---
_Generated by [Claude
Code](https://claude.ai/code/session_0149C4bPjve1UHWcxTtBsPXC)_

Co-authored-by: Claude <noreply@anthropic.com>
Comment thread src/tools/actors/actor_run_response.ts Resolved
The ABORTED nextStep now gives the default dataset's ID, so the model can
point the user at items written before the abort.

Claude-Session: https://claude.ai/code/session_0149C4bPjve1UHWcxTtBsPXC
jirispilka added a commit that referenced this pull request Oct 14, 2026
)

## Why

Closes apify/ai-team#334

Review page with before/after examples for this PR and the five related
ones (#1564–#1568): https://claude.ai/artifact/WDRj1nwPnMTP9ktGyg3z3i

`resources/read` and `apify-api-read` returned the account's proxy
password from `/v2/users/me` in plain text. `resources/read` is served
in every session.

## What changed

The JSON redaction that both paths share now covers the `password` key
as well as `urlSigningSecretKey`: the value becomes `[REDACTED]`, the
key stays. The function is renamed from `redactUrlSigningSecretKey` to
`redactJsonSecrets`.

`apify-api-read` with `path: /v2/users/me`, or `resources/read` on the
same URL:

```
Before: "proxy": { "password": "<the proxy password>", "groups": [...] }
Now:    "proxy": { "password": "[REDACTED]", "groups": [...] }
```

Any `password` string value in a JSON body is redacted, for example in
dataset items or a JSON key-value store record, and also in
`apify-api-write` responses, which go through the same function. The key
match is exact (`"password"`, case-sensitive). Text, XML and binary
bodies are unchanged, as for `urlSigningSecretKey`. The response shape,
including `structuredContent`, stays the same; only those values change.
The function is not exported through `internals.js`.

## Notes for reviewers (human-written)

## Proof it works

mcpc on a local build (`--tools=apify-api-read`), checking the field
with jq without printing the body:

| Check | Result |
|---|---|
| `resources-read https://api.apify.com/v2/users/me`:
`.data.proxy.password == "[REDACTED]"` | `true` |
| same: `.data.proxy` still has `password`, `groups` is an array |
`true`, `"array"` |
| same: a proxy password appears anywhere in the text | `false` |
| `tools-call apify-api-read path:="/v2/users/me"`: `structuredContent`
and `content[0].text` password `== "[REDACTED]"` | `true`, `true` |
| same: strings holding a proxy password anywhere in the result | `0` |
| same: `isError`, `statusCode` | `false`, `200` |

New unit tests (failing before the fix) cover `redactJsonSecrets()`,
`readApiResource()` and `apify-api-read` on a `/v2/users/me`-shaped body
with a fake value.

Implemented with Claude Code: code, tests, mcpc probe and this
description. Reviewed by a separate Claude Code review pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_0149C4bPjve1UHWcxTtBsPXC

---
_Generated by [Claude
Code](https://claude.ai/code/session_0149C4bPjve1UHWcxTtBsPXC)_

Co-authored-by: Claude <noreply@anthropic.com>
@jirispilka
jirispilka merged commit 3aee515 into master Oct 14, 2026
16 checks passed
@jirispilka
jirispilka deleted the fix/run-next-step-no-rerun branch October 14, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-ai Issues owned by the AI team. tested Temporary label used only programatically for some analytics.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Run results ask the model to re-run the Actor

4 participants