Skip to content

Commit 92870a6

Browse files
jirispilkaclaudeCopilotCopilot
authored
feat: Split call-actor into data + -widget tools (#724)
* 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>
1 parent b8994a3 commit 92870a6

12 files changed

Lines changed: 364 additions & 42 deletions

src/const.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const USER_AGENT_ORIGIN = 'Origin/mcp-server';
2525
export enum HelperTools {
2626
ACTOR_ADD = 'add-actor',
2727
ACTOR_CALL = 'call-actor',
28+
ACTOR_CALL_WIDGET = 'call-actor-widget',
2829
ACTOR_GET_DETAILS = 'fetch-actor-details',
2930
ACTOR_GET_DETAILS_WIDGET = 'fetch-actor-details-widget',
3031
ACTOR_OUTPUT_GET = 'get-actor-output',

src/tools/apps/call_actor.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import log from '@apify/log';
22

33
import { HelperTools } from '../../const.js';
4-
import { getWidgetConfig, WIDGET_URIS } from '../../resources/widgets.js';
54
import type { InternalToolArgs, ToolEntry } from '../../types.js';
65
import { extractActorId } from '../../utils/tools.js';
76
import {
@@ -22,8 +21,8 @@ const CALL_ACTOR_APPS_DESCRIPTION = buildCallActorDescription({
2221

2322
/**
2423
* Apps mode call-actor tool.
25-
* Always runs asynchronously — starts the run and returns immediately with widget metadata.
26-
* The widget automatically tracks progress and updates the UI.
24+
* Always runs asynchronously — starts the run and returns immediately with runId.
25+
* Renders no widget; for a live progress UI, use the call-actor-widget sibling.
2726
*/
2827
export const appsCallActor: ToolEntry = Object.freeze({
2928
type: 'internal',
@@ -33,10 +32,6 @@ export const appsCallActor: ToolEntry = Object.freeze({
3332
outputSchema: callActorOutputSchema,
3433
ajvValidate: callActorAjvValidate,
3534
paymentRequired: true,
36-
// apps-only tool; apps-mode _meta (ui/* and openai/* keys) stripped in non-apps mode by stripWidgetMeta() in src/utils/tools.ts
37-
_meta: {
38-
...getWidgetConfig(WIDGET_URIS.ACTOR_RUN)?.meta,
39-
},
4035
annotations: {
4136
title: 'Call Actor',
4237
readOnlyHint: false,
@@ -45,7 +40,7 @@ export const appsCallActor: ToolEntry = Object.freeze({
4540
openWorldHint: true,
4641
},
4742
call: async (toolArgs: InternalToolArgs) => {
48-
const preResult = await callActorPreExecute(toolArgs);
43+
const preResult = await callActorPreExecute(toolArgs, { route: HelperTools.ACTOR_CALL });
4944
if ('earlyResponse' in preResult) {
5045
return preResult.earlyResponse;
5146
}
@@ -75,7 +70,7 @@ export const appsCallActor: ToolEntry = Object.freeze({
7570
actorName: baseActorName,
7671
actorRun,
7772
input,
78-
widget: true,
73+
widget: false,
7974
});
8075
return {
8176
...response,
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import dedent from 'dedent';
2+
import { z } from 'zod';
3+
4+
import log from '@apify/log';
5+
6+
import { HelperTools } from '../../const.js';
7+
import { getWidgetConfig, WIDGET_URIS } from '../../resources/widgets.js';
8+
import type { InternalToolArgs, ToolEntry, ToolInputSchema } from '../../types.js';
9+
import { compileSchema } from '../../utils/ajv.js';
10+
import { buildMCPResponse } from '../../utils/mcp.js';
11+
import { extractActorId } from '../../utils/tools.js';
12+
import {
13+
buildCallActorErrorResponse,
14+
buildStartAsyncResponse,
15+
callActorPreExecute,
16+
resolveAndValidateActor,
17+
} from '../core/call_actor_common.js';
18+
import { callActorOutputSchema } from '../structured_output_schemas.js';
19+
20+
/**
21+
* Widget-only input: `actor` + `input` + optional `callOptions`.
22+
*
23+
* This schema is declared as `.strict()` so the widget tool's contract excludes stray keys
24+
* such as `async` or `previewOutput`. AJV may also remove unknown properties at the server
25+
* boundary, but any non-AJV execution path must explicitly parse with this schema in the
26+
* handler to enforce the same runtime contract. The widget is always async.
27+
*
28+
* The widget variant does not support MCP `actor:toolName` syntax — use `call-actor` for that.
29+
*/
30+
const callActorWidgetArgsSchema = z.object({
31+
actor: z.string()
32+
.describe('The name of the Actor to call. Format: "username/name" (e.g., "apify/rag-web-browser").'),
33+
input: z.object({}).passthrough()
34+
.describe('The input JSON to pass to the Actor. Required.'),
35+
callOptions: z.object({
36+
memory: z.number()
37+
.min(128, 'Memory must be at least 128 MB')
38+
.max(32768, 'Memory cannot exceed 32 GB (32768 MB)')
39+
.optional()
40+
.describe(dedent`
41+
Memory allocation for the Actor in MB. Must be a power of 2 (e.g., 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768).
42+
Minimum: 128 MB, Maximum: 32768 MB (32 GB).
43+
`),
44+
timeout: z.number()
45+
.min(0, 'Timeout must be 0 or greater')
46+
.optional()
47+
.describe(dedent`
48+
Maximum runtime for the Actor in seconds. After this time elapses, the Actor will be automatically terminated.
49+
Use 0 for infinite timeout (no time limit). Minimum: 0 seconds (infinite).
50+
`),
51+
}).optional()
52+
.describe('Optional call options for the Actor run configuration.'),
53+
}).strict();
54+
55+
const CALL_ACTOR_WIDGET_DESCRIPTION = dedent`
56+
Render an interactive UI element (widget) that displays live Actor run progress for the user.
57+
58+
Use this tool ONLY when the user explicitly wants to see run progress visually
59+
(e.g., "run apify/rag-web-browser and show progress", "start this Actor with a progress view").
60+
The response renders as an interactive widget that automatically tracks run status until
61+
completion — do NOT poll or call any other tool after this.
62+
63+
For silent async starts where no UI is needed (e.g., "start this in the background",
64+
or when your next step is to fetch results via ${HelperTools.ACTOR_OUTPUT_GET}), use
65+
${HelperTools.ACTOR_CALL} instead — it returns the same runId without rendering a widget.
66+
67+
WORKFLOW:
68+
1. Use ${HelperTools.ACTOR_GET_DETAILS} to get the Actor's input schema
69+
2. Call this tool with the actor name and proper input based on the schema
70+
71+
If the actor name is not in "username/name" format, use ${HelperTools.STORE_SEARCH} to resolve the correct Actor first.
72+
73+
Input: actor name and input JSON; callOptions (memory, timeout) are optional.
74+
`;
75+
76+
export const appsCallActorWidget: ToolEntry = Object.freeze({
77+
type: 'internal',
78+
name: HelperTools.ACTOR_CALL_WIDGET,
79+
description: CALL_ACTOR_WIDGET_DESCRIPTION,
80+
inputSchema: z.toJSONSchema(callActorWidgetArgsSchema) as ToolInputSchema,
81+
outputSchema: callActorOutputSchema,
82+
// Allow arbitrary keys inside `input` (dynamic Actor input) while keeping the outer shape strict.
83+
ajvValidate: compileSchema(z.toJSONSchema(callActorWidgetArgsSchema)),
84+
paymentRequired: true,
85+
// Tool-level widget meta; only registered in apps mode so stripWidgetMeta is a no-op here.
86+
_meta: {
87+
...getWidgetConfig(WIDGET_URIS.ACTOR_RUN)?.meta,
88+
},
89+
annotations: {
90+
title: 'Call Actor (widget)',
91+
readOnlyHint: false,
92+
destructiveHint: true,
93+
idempotentHint: false,
94+
openWorldHint: true,
95+
},
96+
call: async (toolArgs: InternalToolArgs) => {
97+
const rawActor = toolArgs.args?.actor;
98+
if (typeof rawActor === 'string' && rawActor.includes(':')) {
99+
return buildMCPResponse({
100+
texts: [
101+
`${HelperTools.ACTOR_CALL_WIDGET} does not render widgets for MCP tool calls.`,
102+
`Use ${HelperTools.ACTOR_CALL} for the "actorName:toolName" syntax.`,
103+
],
104+
isError: true,
105+
});
106+
}
107+
108+
const preResult = await callActorPreExecute(toolArgs, { route: HelperTools.ACTOR_CALL_WIDGET });
109+
if ('earlyResponse' in preResult) {
110+
return preResult.earlyResponse;
111+
}
112+
113+
const { parsed, baseActorName } = preResult;
114+
const { input, callOptions } = parsed;
115+
116+
let resolvedActorId: string | undefined;
117+
try {
118+
const resolution = await resolveAndValidateActor({
119+
actorName: baseActorName,
120+
input: input as Record<string, unknown>,
121+
toolArgs,
122+
});
123+
if ('error' in resolution) {
124+
return resolution.error;
125+
}
126+
127+
resolvedActorId = extractActorId(resolution.actor);
128+
const { apifyClient } = toolArgs;
129+
130+
const actorClient = apifyClient.actor(baseActorName);
131+
const actorRun = await actorClient.start(input, callOptions);
132+
log.debug('Started Actor run (widget)', { actorName: baseActorName, runId: actorRun.id, mcpSessionId: toolArgs.mcpSessionId });
133+
const response = buildStartAsyncResponse({
134+
actorName: baseActorName,
135+
actorRun,
136+
input,
137+
widget: true,
138+
});
139+
return {
140+
...response,
141+
toolTelemetry: { actorId: resolvedActorId },
142+
};
143+
} catch (error) {
144+
return buildCallActorErrorResponse({
145+
actorName: baseActorName,
146+
error,
147+
actorId: resolvedActorId,
148+
isAsync: true,
149+
mcpSessionId: toolArgs.mcpSessionId,
150+
actorGetDetailsTool: HelperTools.ACTOR_GET_DETAILS,
151+
});
152+
}
153+
},
154+
} as const);

src/tools/categories.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import type { ToolEntry } from '../types.js';
1717
import { ServerMode } from '../types.js';
1818
import { appsCallActor } from './apps/call_actor.js';
19+
import { appsCallActorWidget } from './apps/call_actor_widget.js';
1920
import { fetchActorDetailsWidgetTool } from './apps/fetch_actor_details_widget.js';
2021
import { appsGetActorRun } from './apps/get_actor_run.js';
2122
import { searchActorsWidgetTool } from './apps/search_actors_widget.js';
@@ -74,6 +75,7 @@ export const toolCategories = {
7475
ui: [
7576
{ apps: searchActorsWidgetTool },
7677
{ apps: fetchActorDetailsWidgetTool },
78+
{ apps: appsCallActorWidget },
7779
],
7880
docs: [
7981
searchApifyDocsTool,

src/tools/core/call_actor_common.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ export function buildCallActorDescription(params: CallActorDescriptionParams): s
9999
if (alwaysAsync) {
100100
sections.push(dedent`
101101
IMPORTANT:
102-
- This tool always runs asynchronously — it starts the Actor and returns immediately with a runId. A live widget automatically tracks the run progress.
103-
- After calling this tool, do NOT poll or call any other tool. Wait for the user to respond — the widget will update them when the run completes.
102+
- This tool always runs asynchronously — it starts the Actor and returns immediately with a runId. It renders no UI.
103+
- For a live progress widget the user can watch, call ${HelperTools.ACTOR_CALL_WIDGET} instead.
104+
- To check status or wait for completion, poll ${HelperTools.ACTOR_RUNS_GET} with the runId.
104105
- Once the run completes, use ${HelperTools.ACTOR_OUTPUT_GET} tool with the datasetId to fetch full results.
105106
- Use dedicated Actor tools when available for better experience
106107
`);
@@ -463,7 +464,10 @@ export async function resolveAndValidateActor(params: {
463464
* clients cannot pass a clean-enough id for definition fetch but a dirty id to `apifyClient.actor()` (see Mezmo:
464465
* e.g. trailing `` ` `` on `apify/rag-web-browser`).
465466
*/
466-
export async function callActorPreExecute(toolArgs: InternalToolArgs): Promise<
467+
export async function callActorPreExecute(
468+
toolArgs: InternalToolArgs,
469+
options: { route: string },
470+
): Promise<
467471
| { earlyResponse: object }
468472
| {
469473
parsed: CallActorParsedArgs;
@@ -473,7 +477,7 @@ export async function callActorPreExecute(toolArgs: InternalToolArgs): Promise<
473477
> {
474478
const { args, apifyToken, apifyMcpServer, mcpSessionId } = toolArgs;
475479
const parsedArgs = callActorArgs.parse(args);
476-
const actorName = fixActorNameInputAndLog(parsedArgs.actor, { mcpSessionId, route: 'call-actor' });
480+
const actorName = fixActorNameInputAndLog(parsedArgs.actor, { mcpSessionId, route: options.route });
477481
const parsed: CallActorParsedArgs = { ...parsedArgs, actor: actorName };
478482

479483
const { baseActorName, mcpToolName } = resolveActorContext(parsed.actor);

src/tools/core/get_actor_run_common.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,10 @@ export const getActorRunArgs = z.object({
2424
const GET_ACTOR_RUN_DESCRIPTION = `Get detailed information about a specific Actor run by runId.
2525
The results will include run metadata (status, timestamps), performance stats, and resource IDs (datasetId, keyValueStoreId, requestQueueId).
2626
27-
CRITICAL WARNING: NEVER call this tool immediately after call-actor in UI mode. The call-actor response includes a widget that automatically polls for updates. Calling this tool after call-actor is FORBIDDEN and unnecessary.
28-
2927
USAGE:
30-
- Use ONLY when user explicitly asks about a specific run's status or details.
31-
- Use ONLY for runs that were started outside the current conversation.
32-
- DO NOT use this tool as part of the call-actor workflow in UI mode.
28+
- Use when the user asks about a specific run's status or details.
29+
- Use to check the status of a run started with call-actor (e.g., before fetching output).
30+
- If you used call-actor-widget and a widget was rendered, do not poll get-actor-run; the widget handles status.
3331
3432
USAGE EXAMPLES:
3533
- user_input: Show details of run y2h7sK3Wc (where y2h7sK3Wc is an existing run)

src/tools/default/call_actor.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import log from '@apify/log';
22

33
import { HelperTools } from '../../const.js';
4-
import { getWidgetConfig, WIDGET_URIS } from '../../resources/widgets.js';
54
import type { InternalToolArgs, ToolEntry } from '../../types.js';
65
import { buildUsageMeta } from '../../utils/mcp.js';
76
import { extractActorId } from '../../utils/tools.js';
@@ -36,10 +35,6 @@ export const defaultCallActor: ToolEntry = Object.freeze({
3635
outputSchema: callActorOutputSchema,
3736
ajvValidate: callActorAjvValidate,
3837
paymentRequired: true,
39-
// openai/* and ui keys are stripped in non-apps mode by stripWidgetMeta() in src/utils/tools.ts
40-
_meta: {
41-
...getWidgetConfig(WIDGET_URIS.ACTOR_RUN)?.meta,
42-
},
4338
annotations: {
4439
title: 'Call Actor',
4540
readOnlyHint: false,
@@ -52,7 +47,7 @@ export const defaultCallActor: ToolEntry = Object.freeze({
5247
taskSupport: 'optional',
5348
},
5449
call: async (toolArgs: InternalToolArgs) => {
55-
const preResult = await callActorPreExecute(toolArgs);
50+
const preResult = await callActorPreExecute(toolArgs, { route: HelperTools.ACTOR_CALL });
5651
if ('earlyResponse' in preResult) {
5752
return preResult.earlyResponse;
5853
}

src/utils/server-instructions/index.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* see widget tool names like `search-actors-widget` or `fetch-actor-details-widget`,
77
* avoiding hallucinated calls to tools absent from `tools/list`.
88
*
9-
* Note: the `-widget` suffix split is rolling out per-tool.
10-
* `fetch-actor-details` and `search-actors` are already split; `call-actor` and
11-
* `get-actor-run` still render widgets on their base names until their own splits land.
9+
* Note: the `-widget` suffix split is rolling out per-tool. `fetch-actor-details`,
10+
* `search-actors`, and `call-actor` are already split; `get-actor-run` still renders
11+
* a widget on its base name until its own split lands.
1212
*/
1313

1414
import { HelperTools, RAG_WEB_BROWSER } from '../../const.js';
@@ -52,20 +52,20 @@ ${isApps ? `
5252
## Widget workflow (applies when tool responses include widget metadata)
5353
Some clients render widget-backed Actor tools: the response includes a live UI that automatically polls run status. When a widget is rendered, follow-up status polling by the model is a forbidden duplicate.
5454
55-
- **Never call \`${HelperTools.ACTOR_RUNS_GET}\` after a widget-backed \`${HelperTools.ACTOR_CALL}\` response.** The widget renders live progress and polls itself — stop after the widget response and defer to it for run status.
56-
- When \`${HelperTools.ACTOR_CALL}\` runs without a widget (the tool response is plain text / structured data only), polling \`${HelperTools.ACTOR_RUNS_GET}\` for status is expected.
57-
- The \`-widget\` suffix split is rolling out per-tool (\`${HelperTools.ACTOR_GET_DETAILS_WIDGET}\` and \`${HelperTools.STORE_SEARCH_WIDGET}\` already split); until the rest split, widget rendering happens on the base \`${HelperTools.ACTOR_CALL}\` and \`${HelperTools.ACTOR_RUNS_GET}\` tool names when the client supports it.
55+
- **Never call \`${HelperTools.ACTOR_RUNS_GET}\` after \`${HelperTools.ACTOR_CALL_WIDGET}\`.** The widget renders live progress and polls itself — stop after the widget response and defer to it for run status.
56+
- Polling \`${HelperTools.ACTOR_RUNS_GET}\` after \`${HelperTools.ACTOR_CALL}\` (the silent async variant, no widget) is fine — that tool renders no UI, so polling is expected when you need the run status.
5857
` : ''}
5958
## Tool dependencies and disambiguation
6059
6160
### Tool dependencies
6261
- \`${HelperTools.ACTOR_CALL}\`:
6362
- Use \`${HelperTools.ACTOR_GET_DETAILS}\` first to obtain the Actor's input schema.
6463
- Then call with proper input to execute the Actor.
65-
- For MCP server Actors, use format "actorName:toolName" to call specific tools.
64+
- For MCP server Actors, use format "actorName:toolName" to call specific tools.${isApps ? `
65+
- In this mode \`${HelperTools.ACTOR_CALL}\` always runs asynchronously — it starts the run and returns immediately with a runId. Use \`${HelperTools.ACTOR_RUNS_GET}\` to check status and \`${HelperTools.ACTOR_OUTPUT_GET}\` to fetch output once the run completes.` : `
6666
- Supports async execution via the \`async\` parameter:
6767
- \`async: false\` or unset: waits for completion and returns results immediately.
68-
- \`async: true\`: starts the run and returns immediately with a runId.
68+
- \`async: true\`: starts the run and returns immediately with a runId.`}
6969
7070
### Tool disambiguation
7171
- **\`${HelperTools.ACTOR_OUTPUT_GET}\` vs \`${HelperTools.DATASET_GET_ITEMS}\`:**
@@ -75,6 +75,7 @@ Some clients render widget-backed Actor tools: the response includes a live UI t
7575
${isApps ? `- **Data vs widget Actor tools (when the client supports widgets):**
7676
- \`${HelperTools.STORE_SEARCH}\` is a silent data lookup (Actor list for name resolution) with no UI; \`${HelperTools.STORE_SEARCH_WIDGET}\` renders an interactive UI element (widget) with Actor search results for the user to browse — use it only when the user explicitly asks to search or discover Actors.
7777
- \`${HelperTools.ACTOR_GET_DETAILS}\` is a silent data lookup (input schema, README, metadata) with no UI; \`${HelperTools.ACTOR_GET_DETAILS_WIDGET}\` renders an interactive UI element (widget) with Actor details — use it only when the user explicitly asks to see or browse the Actor.
78+
- \`${HelperTools.ACTOR_CALL}\` is a silent async start (returns runId, no UI); \`${HelperTools.ACTOR_CALL_WIDGET}\` renders an interactive UI element (widget) that tracks live Actor run progress — use it only when the user explicitly asks to see progress.
7879
- When the next step is running an Actor, prefer silent lookups (\`${HelperTools.STORE_SEARCH}\`, \`${HelperTools.ACTOR_GET_DETAILS}\`) over widget-backed variants.
7980
` : ''}- **\`${HelperTools.STORE_SEARCH}\` vs ${RAG_WEB_BROWSER}:**
8081
\`${HelperTools.STORE_SEARCH}\` finds robust and reliable Actors for specific websites; ${RAG_WEB_BROWSER} is a general and versatile web scraping tool.

0 commit comments

Comments
 (0)