Skip to content

feat: Split fetch-actor-details into data + -widget tools#722

Merged
jirispilka merged 5 commits intomasterfrom
claude/implement-issue-716-5kTwG
Apr 27, 2026
Merged

feat: Split fetch-actor-details into data + -widget tools#722
jirispilka merged 5 commits intomasterfrom
claude/implement-issue-716-5kTwG

Conversation

@jirispilka
Copy link
Copy Markdown
Collaborator

@jirispilka jirispilka commented Apr 19, 2026

PR chain — part of #577

Step 3 of 6. Stacked on #721; rebase to master once #720+#721 merge.

closes #716

# Issue PR
1 #714 #720 (merged)
2 #715 #721 (merged)
3 #716 this PR
4 #717 #723
5 #718 #724
6 #719 #734

Closes #716.

Summary

Pilot of the decoupled pattern on fetch-actor-details:

  • fetch-actor-details is mode-independent, data-only. No widget _meta on the base tool in either mode.
  • New fetch-actor-details-widget (apps-only). Strict input (actor only). Output: { actorDetails: { actorInfo, actorCard, readme } }.
  • fetch-actor-details-internal removed — base tool covers silent lookup.

File history preserved via git mv src/tools/apps/fetch_actor_details.ts src/tools/apps/fetch_actor_details_widget.ts.

Test plan

  • npm run type-check
  • npm run lint
  • npm run test:unit (597/597)
  • npm run build
  • JSON-RPC probe matrix — tools/list stable, no tools/list_changed:
    • default (no UI caps) → fetch-actor-details only, no widget _meta
    • auto + UI extension → base + -widget (widget ui.resourceUri, visibility=[model,app], non-empty csp)
    • --ui on → same as auto+UI (forced)
    • --ui off + UI caps → same as default (override wins)
  • Integration tests (widget-meta + ActorSearchDetail paths on stdio/SSE/streamable-HTTP)
  • MCPJam widget round-trip (human)

`apify-mcp-server-internal` impact

  • `ACTOR_GET_DETAILS_INTERNAL` enum member and `fetch-actor-details-internal` string removed.
  • Base `fetch-actor-details` no longer carries widget `_meta` — readers must switch to `fetch-actor-details-widget`.
  • Widget `structuredContent` shape is `{ actorDetails: { actorInfo, actorCard, readme } }` — matches `ActorSearchDetail.tsx`.

https://claude.ai/code/session_01ZsYYZ6u64jAWyxj3GTPwpG

jirispilka pushed a commit that referenced this pull request Apr 19, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 20, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 20, 2026
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
@jirispilka jirispilka force-pushed the claude/auto-detect-mcp-apps-gLMu1 branch from 112d214 to f9c12ca Compare April 20, 2026 21:35
@jirispilka jirispilka force-pushed the claude/implement-issue-716-5kTwG branch from 527ad06 to e23510a Compare April 20, 2026 21:35
jirispilka pushed a commit that referenced this pull request Apr 20, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 20, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 20, 2026
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
@jirispilka jirispilka force-pushed the claude/implement-issue-716-5kTwG branch 2 times, most recently from c88e25a to 5909cb6 Compare April 22, 2026 12:53
jirispilka pushed a commit that referenced this pull request Apr 22, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 22, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 22, 2026
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
@jirispilka jirispilka marked this pull request as ready for review April 23, 2026 18:38
@jirispilka jirispilka requested a review from Copilot April 23, 2026 18:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements the decoupled “data tool + -widget sibling” pattern for fetch-actor-details, making the base tool mode-independent and introducing an apps-only widget tool for UI rendering.

Changes:

  • Removes widget _meta from the base fetch-actor-details tool and makes it shared across modes.
  • Adds fetch-actor-details-widget (apps-only) with strict actor-only input and widget-shaped structured output.
  • Updates tool registration, constants, server instructions, and unit/integration tests to reflect the new tool split and removal of fetch-actor-details-internal.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/const.ts Replaces ACTOR_GET_DETAILS_INTERNAL with ACTOR_GET_DETAILS_WIDGET.
src/tools/categories.ts Makes fetch-actor-details mode-independent; registers fetch-actor-details-widget in ui (apps-only).
src/tools/core/fetch_actor_details_common.ts Removes tool-level widget _meta; simplifies base handler route handling.
src/tools/default/fetch_actor_details.ts Updates base tool call to match new shared handler signature.
src/tools/structured_output_schemas.ts Adds actorDetailsWidgetOutputSchema for the new widget tool.
src/tools/apps/fetch_actor_details_widget.ts Introduces the new apps-only widget tool implementation.
src/tools/apps/fetch_actor_details.ts Deletes old apps-mode variant (widget-on-base behavior).
src/tools/apps/fetch_actor_details_internal.ts Deletes the old internal silent lookup tool.
src/tools/apps/search_actors.ts Updates guidance text to steer between base vs widget details tools.
src/tools/core/call_actor_common.ts Narrows helper-tool typing to the base details tool (no internal variant).
src/tools/apps/call_actor.ts Updates to reference the base details tool constant.
src/utils/server-instructions/index.ts Updates rollout/disambiguation wording for the per-tool -widget migration.
tests/unit/utils.tools_loader.test.ts Updates expected apps UI tool names to include the new widget tool.
tests/unit/tools.search_actors.widget.response.test.ts Updates expected instruction text to reference fetch-actor-details-widget + base tool.
tests/unit/tools.mode_contract.test.ts Updates apps ui category expectations; adds assertion that base details tool has no widget meta.
tests/unit/tools.call_actor_common.test.ts Updates expected helper-tool names in apps descriptions/error responses.
tests/unit/tools.fetch_actor_details.widget.response.test.ts Adds unit coverage for the new widget tool response/meta/schema behavior.
tests/integration/suite.ts Updates integration expectations to call/validate fetch-actor-details-widget in apps mode.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tools/apps/fetch_actor_details_widget.ts Outdated
Comment thread tests/unit/tools.fetch_actor_details.widget.response.test.ts Outdated
Comment thread src/tools/core/fetch_actor_details_common.ts
@jirispilka
Copy link
Copy Markdown
Collaborator Author

@copilot please fix all the review comments, they make sense

jirispilka pushed a commit that referenced this pull request Apr 24, 2026
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
MQ37
MQ37 approved these changes Apr 27, 2026
Copy link
Copy Markdown
Contributor

@MQ37 MQ37 left a comment

Choose a reason for hiding this comment

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

LGTM — solid refactor, great tests.

One personal preference on naming: I find getActors() and getActorsAsTools() confusing since both return ToolEntry[] but at different abstraction levels. I'd suggest:

  • getActorsAsToolsfetchActorsAsTools (it hits the Apify API)
  • getActorsgetActorsFromInput (resolves actor names from Input)

Not blocking — ship it!

@jirispilka jirispilka force-pushed the claude/refactor-ui-handling-amyRL branch from b784f4d to 6cc397d Compare April 27, 2026 11:29
@jirispilka jirispilka force-pushed the claude/implement-issue-716-5kTwG branch from 28c8530 to 72114c7 Compare April 27, 2026 11:30
jirispilka pushed a commit that referenced this pull request Apr 27, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 27, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 27, 2026
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
Base automatically changed from claude/refactor-ui-handling-amyRL to master April 27, 2026 18:07
@jirispilka jirispilka force-pushed the claude/implement-issue-716-5kTwG branch from 72114c7 to 80e059a Compare April 27, 2026 18:22
claude and others added 5 commits April 27, 2026 20:26
Decoupled-pattern pilot (#716, part of #577):
- fetch-actor-details is now one mode-independent tool returning pure data.
- New fetch-actor-details-widget (apps-only) renders the interactive UI
  element with only { actorDetails: { actorInfo, readme } }.
- Removed fetch-actor-details-internal; the base tool now serves the silent
  lookup role.
- Updated apps server instructions and search-actors/call-actor guidance to
  steer between silent data lookups and widget rendering.

https://claude.ai/code/session_01ZsYYZ6u64jAWyxj3GTPwpG
…improve server instructions

- Renamed `detectClientSupportsUi` to `isUiSupportedByClient` for better readability and alignment with other methods.
- Updated initialize handler to include mode-aware server instructions in response payload.
- Enhanced `getServerInstructions` to dynamically include apps-specific sections based on server mode, avoiding irrelevant content for default-mode clients.
…riant refs, actorCard in widget contract

- `fetchActorDetailsWidgetArgsSchema` comment now reflects that AJV
  `removeAdditional: true` silently strips stray keys (Zod `.strict()` is
  belt-and-braces for any path that bypasses AJV).
- `fetchActorDetailsToolArgsSchema` / `fetchActorDetailsMetadata` docstrings
  no longer claim a separate "apps variant" exists — the base tool is
  mode-independent and the `-widget` sibling has its own schema/metadata.
- Widget response test docstring + it-title + assertions now match the
  actual `{ actorDetails: { actorInfo, actorCard, readme } }` contract.

https://claude.ai/code/session_01ZsYYZ6u64jAWyxj3GTPwpG
@jirispilka jirispilka force-pushed the claude/implement-issue-716-5kTwG branch from 80e059a to 9b80bc4 Compare April 27, 2026 18:27
@github-actions github-actions Bot added t-ai Issues owned by the AI team. tested Temporary label used only programatically for some analytics. labels Apr 27, 2026
@jirispilka jirispilka merged commit 1a455a5 into master Apr 27, 2026
12 checks passed
@jirispilka jirispilka deleted the claude/implement-issue-716-5kTwG branch April 27, 2026 18:29
jirispilka pushed a commit that referenced this pull request Apr 27, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 27, 2026
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
jirispilka pushed a commit that referenced this pull request Apr 27, 2026
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
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>

---------

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>
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>

---------

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>
jirispilka pushed a commit that referenced this pull request Apr 29, 2026
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
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

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: Split fetch-actor-details into data + -widget tools

6 participants