Skip to content

feat(evals): Add task-tool workflow eval suites - #1294

Open
jirispilka wants to merge 6 commits into
masterfrom
feat/tasks-workflow-evals
Open

feat(evals): Add task-tool workflow eval suites#1294
jirispilka wants to merge 6 commits into
masterfrom
feat/tasks-workflow-evals

Conversation

@jirispilka

@jirispilka jirispilka commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Workflow eval suites for the Actor task tools. Closes #1288.

I created a new dataset specifically for this, we'll merge it later.
I did not want to mixed it up with existing evals as they are not "clean" (=there are errors)
We will improve the test cases later. I think they are overly verbose, no one gonna prompt in that way.

I'm sorry, we'll need to clean this up afterwards but I don't have time for it now 😊

  • Two Langfuse datasets, split on purpose: tasks-evals (7 proper cases) and tasks-evals-errors (3 cases that provoke errors: name collision, not-found lookup, publish-requirement discovery). Error-provoking cases inside a proper suite mask real failures, so they are quarantined and run with --allow-tool-errors.
  • --subscription runs the agent on the local Claude Code login instead of ANTHROPIC_API_KEY.

@github-actions github-actions Bot added t-ai Issues owned by the AI team. tested Temporary label used only programatically for some analytics. labels Aug 20, 2026
@jirispilka
jirispilka force-pushed the feat/tasks-workflow-evals branch from f02eb04 to 2cd3a7e Compare August 20, 2026 21:09
@jirispilka
jirispilka changed the base branch from master to feat/task-input-api-parity August 20, 2026 21:09
jirispilka added a commit that referenced this pull request Aug 21, 2026
…1293)

Task tools now return the stored task `input` verbatim, under the same
key the API, CLI, and apify-client use. Everything in this PR came out
of the task-tool workflow evals (#1294): agents could not answer "what
input is my task configured with?", could not verify their own updates,
and hallucinated values from the field-name list.

Not obvious from the code:

- **Returning the input is safe.** The platform encrypts input fields
declared `isSecret: true` server-side on save. Verified empirically: a
task created via the raw API with a plaintext secret returns
`ENCRYPTED_VALUE:...` from both `GET actor-task` and `GET
actor-task/input`; the plaintext never comes back. Non-secret values are
already returned by every other Apify surface.
- **`seoDescription` is required to publish**, which no docs state —
discovered via API probing after eval agents got stuck. Descriptions now
list the full requirements, and the schema declares the SEO length
limits (60/160) the API enforces.
- **Contract change:** the task tools' `structuredContent` replaces
`inputFields` (names only) with `input`.
- Tool errors append the machine-readable API error type, e.g. `(API
error type: actor-task-name-not-unique)`.
Base automatically changed from feat/task-input-api-parity to master August 21, 2026 09:54
Two Langfuse suites for the Actor task tools, split by doctrine:
tasks-evals (7 proper cases) and tasks-evals-errors (3 error-recovery
cases that provoke failures on purpose). The run gate now requires
zero failed tool calls by default; every item carries a tool_errors
score with the failing calls in the comment, and error suites run with
--allow-tool-errors. Failures injected via failTools are exempt.

Add --subscription (the agent runs on the local Claude Code login
instead of ANTHROPIC_API_KEY), a fixtures seed/cleanup script for the
eval-* tasks, per-dataset snapshot export, and snapshots for both
suites.
A transient SDK connection error dropped a whole item from the run;
the agent conversation now retries once, and a persistent failure
still throws. Some OpenRouter providers occasionally answer the judge
prompt in plain text despite the JSON schema, which discarded a
scored item; the judge call now retries once before failing.

The update-medium case now pins the sequence (create with default run
options, then change them), so setting options at creation can no
longer bypass the update path the case exists to cover.
The gate filtered tool invocations on failure alone, and tool names are
prefix-stripped before it sees them, so a failed Claude Code built-in
(Bash, WebFetch) failed an eval item on a judge PASS. Carry `isMcpTool`
from the adapter, computed on the unstripped name, and count only the
server's own tools.

Also in the harness:
- Truncate tool errors to the first line at capture; the full text
  already sits on the tool span, so it was uploaded three times.
- Extract `judgeScore` and `formatToolErrors`, each written twice.
- Name the judge parse-attempt count and keep the raw response in the
  failure, which the retry had dropped.
- One snapshot file per dataset, dropping the default-name special case.
- Paginate the fixture cleanup and reuse `findMissingEnvVars`.
The query asks the agent to "confirm it's actually live", but the
reference never said what counts as confirmation, so the judge invented a
requirement for a separate lookup and failed runs that had already
published successfully. Say it explicitly: a successful
publish-actor-task is the confirmation, since its response carries
publishedAt.

Also record two things probed against the API: publishing requires all
three of inputSchemaFields, datasetView and seoDescription, and the API
reports missing ones non-exhaustively, which is what task-publish-discovery
spends its turns on. And note task-chain-hard-1's ~6/8 rate on Haiku with
the guessed-slug residual, so a single red run is not read as a break.
Sonnet passes task-chain-hard-1 3/3, Haiku about 5 in 8, and every Haiku
failure is the same constructed Actor name. Records that hardening
fetch-actor-details' description was measured at 5/8 against ~7/10
without it, so the next person does not spend another round rewording
descriptions that already say it twice.
// The Agent SDK's Claude Code subprocess falls back to the local login only when no
// API key is in its environment, which it inherits from this process.
if (argv.subscription) {
delete process.env.ANTHROPIC_API_KEY;

@jirispilka jirispilka Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a good solution but I guess we can live it for now 😊

@jirispilka
jirispilka marked this pull request as draft August 21, 2026 15:12
// far more expensive agent conversation; a second malformed answer still throws.
let lastError: unknown;
let lastRawResponse = '';
for (let attempt = 1; attempt <= JUDGE_PARSE_ATTEMPTS; attempt++) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added attempts, sometimes the judge failed on a slow interner

@jirispilka
jirispilka requested review from MQ37 and RobertCrupa August 22, 2026 20:02
@jirispilka
jirispilka marked this pull request as ready for review August 22, 2026 20:02
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.

feat: Add task tools to the default eval tools

2 participants