Skip to content

test: Add integration test for x402 _meta advertising on paid tools#768

Merged
jirispilka merged 1 commit intoclaude/implement-get-actor-run-MUTXIfrom
feat/x402-meta-integration-test
Apr 28, 2026
Merged

test: Add integration test for x402 _meta advertising on paid tools#768
jirispilka merged 1 commit intoclaude/implement-get-actor-run-MUTXIfrom
feat/x402-meta-integration-test

Conversation

@MQ37
Copy link
Copy Markdown
Contributor

@MQ37 MQ37 commented Apr 28, 2026

Stacked on #734.

Summary

Adds one Streamable-HTTP integration test asserting that tools with `paymentRequired: true` advertise `_meta.x402` (with `scheme`, `network`, `asset`, `payTo`, `amount`) when the server runs with `?payment=x402`, and that free tools do not.

The expected paid set is hardcoded in the test rather than imported from `SKYFIRE_ENABLED_TOOLS` so that silent drift between `paymentRequired` flags and the constant is caught here. This locks in the regression flagged in #734 (where `get-actor-run` lost `paymentRequired: true`).

Tracks #766 (broader plan for automated agentic-payment integration tests).

Tests

  • `npm run type-check` — passes
  • `npm run lint` — passes
  • `npm run test:unit` — 615 passed
  • `npm run test:integration` — human-run per CLAUDE.md

Asserts that tools with paymentRequired: true advertise _meta.x402 with
the expected fields (scheme, network, asset, payTo, amount) when the
server runs in x402 payment mode, and that free tools do not.

Pins the expected paid set with a hardcoded list so silent drift (e.g.
a tool losing paymentRequired) is caught here. Tracks #766.
Copy link
Copy Markdown
Collaborator

@jirispilka jirispilka left a comment

Choose a reason for hiding this comment

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

Thanks 💪🏻

@jirispilka jirispilka merged commit e0ad979 into claude/implement-get-actor-run-MUTXI Apr 28, 2026
8 checks passed
@jirispilka jirispilka deleted the feat/x402-meta-integration-test branch April 28, 2026 11:25
jirispilka pushed a commit that referenced this pull request Apr 28, 2026
…768)

Asserts that tools with paymentRequired: true advertise _meta.x402 with
the expected fields (scheme, network, asset, payTo, amount) when the
server runs in x402 payment mode, and that free tools do not.

Pins the expected paid set with a hardcoded list so silent drift (e.g.
a tool losing paymentRequired) is caught here. Tracks #766.
jirispilka pushed a commit that referenced this pull request Apr 29, 2026
…768)

Asserts that tools with paymentRequired: true advertise _meta.x402 with
the expected fields (scheme, network, asset, payTo, amount) when the
server runs in x402 payment mode, and that free tools do not.

Pins the expected paid set with a hardcoded list so silent drift (e.g.
a tool losing paymentRequired) is caught here. Tracks #766.
jirispilka added a commit that referenced this pull request Apr 29, 2026
* feat: Split get-actor-run into data + -widget tools

Final step (6 of 6) of the #577 umbrella rollout. Mirrors the
decoupled-pattern recipe from #722 (fetch-actor-details), #723
(search-actors), and #724 (call-actor):

- get-actor-run is now mode-independent and data-only. No tool-level
  widget _meta in either mode; runs category entry is a plain ToolEntry
  instead of a mode map.
- New get-actor-run-widget (apps-only) renders the live progress widget.
  Input is strict: { runId } only. Tool- and response-level widget _meta
  (ui.resourceUri = ui://widget/actor-run.html). Reuses the shared
  buildGetActorRunSuccessResponse({ widget: true }) helper.
- buildGetActorRunSuccessResponse widget branch now also sets
  openai/widgetDescription on the response _meta, matching the other
  three widget tools.
- Apps server instructions: added the fourth disambiguation bullet
  pairing get-actor-run (silent data lookup) with get-actor-run-widget
  (live progress widget), using the same vocabulary as the existing
  three splits. WORKFLOW_RULES untouched — the "NEVER poll
  get-actor-run after call-actor-widget" rule is orthogonal.
- Deleted src/tools/apps/get_actor_run.ts; widget rendering now lives
  in the sibling tool rather than a mode toggle.

https://claude.ai/code/session_01SF9P6g91UrVMahn4bLsUNf

* chore: Address staff review findings post-split

- Drop stale rolling-rollout note from server-instructions header (split is now complete)
- Extend "no polling after widget" rule to also cover get-actor-run-widget
- Rename integration test to drop misleading "widget" label (it exercises the data tool)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor: Remove paymentRequired flag from get-actor-run tools

* Update src/tools/core/get_actor_run_common.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/tools/apps/get_actor_run_widget.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* test: Add integration test for x402 _meta advertising on paid tools (#768)

Asserts that tools with paymentRequired: true advertise _meta.x402 with
the expected fields (scheme, network, asset, payTo, amount) when the
server runs in x402 payment mode, and that free tools do not.

Pins the expected paid set with a hardcoded list so silent drift (e.g.
a tool losing paymentRequired) is caught here. Tracks #766.

* feat: Add paymentRequired flag to get-actor-run tools and update documentation

* refactor: Skip tests for auto mode client capabilities and rename itemCount to totalItemCount

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jakub Kopecký <themq37@gmail.com>
jirispilka added a commit that referenced this pull request Apr 29, 2026
* feat: Split search-actors into data + -widget tools

Step 4 of 6 in the #577 umbrella. Mirrors the decoupled-pattern recipe
validated by the fetch-actor-details split in #716 / PR #722:

- search-actors is now a mode-independent plain ToolEntry that returns
  pure data. Identical inputSchema / outputSchema / _meta across default
  and apps modes — no tool-level widget _meta anywhere.
- New search-actors-widget (apps-only) renders the interactive UI element.
  Input is searchActorsBaseArgsSchema.strict() — keywords/limit/offset
  only, stray keys rejected. Tool- and response-level widget _meta.
- search-actors-internal is removed. The base search-actors now serves
  the silent name-resolution role — no LLM-opaque jargon.
- Apps server instructions and call-actor apps description flipped to
  steer between base (silent data) and -widget (renders an interactive
  UI element) using the "interactive UI element / widget" vocabulary.

File history is preserved via git mv search_actors.ts -> search_actors_widget.ts.

https://claude.ai/code/session_01BKQYsF54uFxW7ELzoQbQ3n

* refactor: Remove storeSearchTool and useInternalSearchWarning from call actor descriptions

* refactor: Improve error messaging and response structure for empty actor searches

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: reword .strict() comment to reflect AJV strip behavior; fix singular test

Agent-Logs-Url: https://github.com/apify/apify-mcp-server/sessions/ca1ebeb2-8719-4f87-b715-394215202a55

Co-authored-by: jirispilka <19406805+jirispilka@users.noreply.github.com>

* feat: Split call-actor into data + -widget tools

Step 5 of 6 in the #577 umbrella. Mirrors the decoupled-pattern recipe
from #716/PR #722 (fetch-actor-details) and #723 (search-actors):

- call-actor now always returns pure data in both modes. No tool-level
  widget _meta anywhere, and buildStartAsyncResponse({ widget: false })
  in apps mode returns runId without response-level widget _meta. The
  apps variant still runs asynchronously.
- New call-actor-widget (apps-only) renders the live progress widget.
  Input is strict: { actor, input, callOptions? } only — async and
  previewOutput are rejected. Tool- and response-level widget _meta
  (ui.resourceUri = ui://widget/actor-run.html).
- Apps server instructions reshaped: the "never poll get-actor-run"
  rule now scopes to call-actor-widget only; polling after the silent
  call-actor is fine. Added a third disambiguation bullet pairing
  call-actor with call-actor-widget using the same "interactive UI
  element / widget" vocabulary as the other two splits.
- buildCallActorDescription alwaysAsync branch flipped to describe
  the silent-async behavior and point to call-actor-widget for UI.

https://claude.ai/code/session_01LPzCFY7ReLm8wvmFHJLyun

* fix: Remove storeSearchTool arg dropped from CallActorErrorResponseParams

* fix: Address review findings on call-actor split

- Remove contradictory 'NEVER call in UI mode' block from get-actor-run
  description; server instructions already scope the rule to call-actor-widget.
- Reject MCP actor:tool syntax in call-actor-widget — previously fell through
  to a non-widget response. Drop the misleading "For MCP server Actors" hint
  from the widget input description.
- Thread an explicit route parameter through callActorPreExecute so widget
  vs base traffic separates in telemetry.
- Server instructions: drop call-actor from the stale "still on base names"
  list; scope async-parameter guidance to non-apps mode.
- Widget docstring + test title: match silent-strip behavior (matches the
  correction in 5d4e6dd for the sibling widget).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor: Update ActorSearch widget test to reflect name change in tool

* Update src/tools/apps/call_actor_widget.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/tools/core/get_actor_run_common.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* feat: Split get-actor-run into data + -widget tools

Final step (6 of 6) of the #577 umbrella rollout. Mirrors the
decoupled-pattern recipe from #722 (fetch-actor-details), #723
(search-actors), and #724 (call-actor):

- get-actor-run is now mode-independent and data-only. No tool-level
  widget _meta in either mode; runs category entry is a plain ToolEntry
  instead of a mode map.
- New get-actor-run-widget (apps-only) renders the live progress widget.
  Input is strict: { runId } only. Tool- and response-level widget _meta
  (ui.resourceUri = ui://widget/actor-run.html). Reuses the shared
  buildGetActorRunSuccessResponse({ widget: true }) helper.
- buildGetActorRunSuccessResponse widget branch now also sets
  openai/widgetDescription on the response _meta, matching the other
  three widget tools.
- Apps server instructions: added the fourth disambiguation bullet
  pairing get-actor-run (silent data lookup) with get-actor-run-widget
  (live progress widget), using the same vocabulary as the existing
  three splits. WORKFLOW_RULES untouched — the "NEVER poll
  get-actor-run after call-actor-widget" rule is orthogonal.
- Deleted src/tools/apps/get_actor_run.ts; widget rendering now lives
  in the sibling tool rather than a mode toggle.

https://claude.ai/code/session_01SF9P6g91UrVMahn4bLsUNf

* chore: Address staff review findings post-split

- Drop stale rolling-rollout note from server-instructions header (split is now complete)
- Extend "no polling after widget" rule to also cover get-actor-run-widget
- Rename integration test to drop misleading "widget" label (it exercises the data tool)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor: Remove paymentRequired flag from get-actor-run tools

* Update src/tools/core/get_actor_run_common.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/tools/apps/get_actor_run_widget.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: Pair widget tools with their base tools instead of unconditional UI auto-include

Closes #746.

In apps mode, the loader unconditionally appended every entry of the `ui`
category whenever any non-empty tool selection was made. A caller asking for
`tools: ['docs']` silently received `search-actors-widget`,
`fetch-actor-details-widget`, `call-actor-widget`, and `get-actor-run-widget`
they did not request — including the paid call-actor widget added in #724.

Replace the unconditional `ui` push with a `WIDGET_BY_BASE_TOOL` map keyed by
base tool name. After the resolved tool list is composed (and after
get-actor-run / get-actor-output auto-inject), append a widget if and only if
its base tool is in the result. The existing de-dup pass handles uniqueness.

Removes the now-empty `ui` category. Tests updated to assert the new pairing
behavior end-to-end via `getToolsForServerMode`.

* chore: Note that pairing-pass duplicates are stripped by the de-dup pass

Inline reminder at the widget push so a future reader doesn't add a
redundant `result.some(...)` guard.

* test: Add integration test for x402 _meta advertising on paid tools (#768)

Asserts that tools with paymentRequired: true advertise _meta.x402 with
the expected fields (scheme, network, asset, payTo, amount) when the
server runs in x402 payment mode, and that free tools do not.

Pins the expected paid set with a hardcoded list so silent drift (e.g.
a tool losing paymentRequired) is caught here. Tracks #766.

* feat: Add paymentRequired flag to get-actor-run tools and update documentation

* refactor: Skip tests for auto mode client capabilities and rename itemCount to totalItemCount

* feat: Include widget tools in apps mode for direct selection

* Update tests/unit/utils.tools_loader.test.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* test: Add integration test for x402 _meta advertising on paid tools (#768)

Asserts that tools with paymentRequired: true advertise _meta.x402 with
the expected fields (scheme, network, asset, payTo, amount) when the
server runs in x402 payment mode, and that free tools do not.

Pins the expected paid set with a hardcoded list so silent drift (e.g.
a tool losing paymentRequired) is caught here. Tracks #766.

* feat: Add paymentRequired flag to get-actor-run tools and update documentation

* refactor: Skip tests for auto mode client capabilities and rename itemCount to totalItemCount

* refactor: Simplify tool selection logic in tools_loader and update tests

* feat: Enhance server mode handling for get-actor-run inclusion in tools

* feat: Add additional integration test scripts for actor server functionality

* feat: Update documentation for widget-base tool pairing and enhance test for duplicate handling

* feat: Update types for WIDGET_BY_BASE_TOOL and improve related documentation

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Jakub Kopecký <themq37@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants