Skip to content

Commit 4ccb4f6

Browse files
committed
fix: update Actor card
1 parent 332a59e commit 4ccb4f6

File tree

4 files changed

+47
-21
lines changed

4 files changed

+47
-21
lines changed

src/tools/fetch-actor-details.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,23 @@ USAGE EXAMPLES:
4040
content: [{ type: 'text', text: `Actor information for '${parsed.actor}' was not found. Please check the Actor ID or name and ensure the Actor exists.` }],
4141
};
4242
}
43-
return {
44-
content: [
45-
{ type: 'text', text: `# Actor information\n${details.actorCard}` },
46-
{ type: 'text', text: `# README\n${details.readme}` },
47-
{ type: 'text', text: `# Input schema\n${JSON.stringify(details.inputSchema, null, 0)}` },
48-
],
49-
};
43+
44+
const actorUrl = `https://apify.com/${details.actorInfo.username}/${details.actorInfo.name}`;
45+
// Add link to README title
46+
details.readme = details.readme.replace(/^# /, `# [README](${actorUrl}/readme): `);
47+
48+
const content = [
49+
{ type: 'text', text: `# Actor information\n${details.actorCard}` },
50+
{ type: 'text', text: `${details.readme}` },
51+
];
52+
53+
// Include input schema if it has properties
54+
if (details.inputSchema.properties || Object.keys(details.inputSchema.properties).length !== 0) {
55+
content.push({ type: 'text', text: `# [Input schema](${actorUrl}/input)\n\`\`\`json\n${JSON.stringify(details.inputSchema, null, 0)}\n\`\`\`` });
56+
}
57+
// Return the actor card, README, and input schema (if it has non-empty properties) as separate text blocks
58+
// This allows better formatting in the final output
59+
return { content };
5060
},
5161
} as InternalTool,
5262
};

src/tools/store_collection.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,11 @@ USAGE EXAMPLES:
105105
{
106106
type: 'text',
107107
text: `
108-
**Search query:** ${parsed.search}
109-
**Number of Actors found:** ${actorCards.length}
110-
**Actor cards:**
108+
# Search results:
109+
- **Search query:** ${parsed.search}
110+
- **Number of Actors found:** ${actorCards.length}
111+
112+
# Actors:
111113
112114
${actorCards.join('\n\n')}`,
113115
},

src/utils/actor-card.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,16 @@ export function formatActorToActorCard(
4242
}
4343

4444
const actorFullName = `${actor.username}/${actor.name}`;
45+
const actorUrl = `${APIFY_STORE_URL}/${actorFullName}`;
4546

4647
// Build the markdown lines
4748
const markdownLines = [
48-
`## ${actor.title} (\`${actorFullName}\`)`,
49-
`- **URL:** ${APIFY_STORE_URL}/${actorFullName}`,
50-
`- **Developed by:** [${actor.username}](${APIFY_STORE_URL}) ${actor.username === 'apify' ? '(Apify)' : '(community)'}`,
49+
`## [${actor.title}](${actorUrl}) (\`${actorFullName}\`)`,
50+
`- **URL:** ${actorUrl}`,
51+
`- **Developed by:** [${actor.username}](${APIFY_STORE_URL}/${actor.username}) ${actor.username === 'apify' ? '(Apify)' : '(community)'}`,
5152
`- **Description:** ${actor.description || 'No description provided.'}`,
5253
`- **Categories:** ${formattedCategories.length ? formattedCategories.join(', ') : 'Uncategorized'}`,
53-
`- **Pricing:** ${pricingInfo}`,
54+
`- **[Pricing](${actorUrl}/pricing):** ${pricingInfo}`,
5455
];
5556

5657
// Add stats - handle different stat structures
@@ -81,18 +82,18 @@ export function formatActorToActorCard(
8182
}
8283

8384
if (statsParts.length > 0) {
84-
markdownLines.push(`**Stats:** ${statsParts.join(', ')}`);
85+
markdownLines.push(`- **Stats:** ${statsParts.join(', ')}`);
8586
}
8687
}
8788

8889
// Add rating if available (ActorStoreList only)
8990
if ('actorReviewRating' in actor && actor.actorReviewRating) {
90-
markdownLines.push(`**Rating:** ${actor.actorReviewRating.toFixed(2)} out of 5`);
91+
markdownLines.push(`- **Rating:** ${actor.actorReviewRating.toFixed(2)} out of 5`);
9192
}
9293

9394
// Add modification date if available
9495
if ('modifiedAt' in actor) {
95-
markdownLines.push(`**Last modified:** ${actor.modifiedAt.toISOString()}`);
96+
markdownLines.push(`- **Last modified:** ${actor.modifiedAt.toISOString()}`);
9697
}
9798

9899
// Add deprecation warning if applicable

src/utils/pricing-info.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,24 @@ function convertMinutesToGreatestUnit(minutes: number): { value: number; unit: s
4141
return { value: Math.floor(minutes / (60 * 24)), unit: 'days' };
4242
}
4343

44+
/**
45+
* Formats the pay-per-event pricing information into a human-readable string.
46+
*
47+
* Example:
48+
* This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for the following events:
49+
* - Event title: Event description (Flat price: $X per event)
50+
* - MCP server startup: Initial fee for starting the Kiwi MCP Server Actor (Flat price: $0.1 per event)
51+
* - Flight search: Fee for searching flights using the Kiwi.com flight search engine (Flat price: $0.001 per event)
52+
*
53+
* For tiered pricing, the output is more complicated and the question is whether we want to simplify it in the future.
54+
* @param pricingPerEvent
55+
*/
56+
4457
function payPerEventPricingToString(pricingPerEvent: ExtendedPricingInfo['pricingPerEvent']): string {
4558
if (!pricingPerEvent || !pricingPerEvent.actorChargeEvents) return 'No event pricing information available.';
4659
const eventStrings: string[] = [];
4760
for (const event of Object.values(pricingPerEvent.actorChargeEvents)) {
48-
let eventStr = `- ${event.eventTitle}: ${event.eventDescription} `;
61+
let eventStr = `\t- **${event.eventTitle}**: ${event.eventDescription} `;
4962
if (typeof event.eventPriceUsd === 'number') {
5063
eventStr += `(Flat price: $${event.eventPriceUsd} per event)`;
5164
} else if (event.eventTieredPricingUsd) {
@@ -58,14 +71,14 @@ function payPerEventPricingToString(pricingPerEvent: ExtendedPricingInfo['pricin
5871
}
5972
eventStrings.push(eventStr);
6073
}
61-
return `This Actor charges per event as follows:\n${eventStrings.join('\n')}`;
74+
return `This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for the following events:\n${eventStrings.join('\n')}`;
6275
}
6376

6477
export function pricingInfoToString(pricingInfo: ExtendedPricingInfo | null): string {
6578
// If there is no pricing infos entries the Actor is free to use
6679
// based on https://github.com/apify/apify-core/blob/058044945f242387dde2422b8f1bef395110a1bf/src/packages/actor/src/paid_actors/paid_actors_common.ts#L691
6780
if (pricingInfo === null || pricingInfo.pricingModel === ACTOR_PRICING_MODEL.FREE) {
68-
return 'This Actor is free to use; the user only pays for the computing resources consumed by the Actor.';
81+
return 'User pays for the computing resources consumed by the Actor';
6982
}
7083
if (pricingInfo.pricingModel === ACTOR_PRICING_MODEL.PRICE_PER_DATASET_ITEM) {
7184
const customUnitName = pricingInfo.unitName !== 'result' ? pricingInfo.unitName : '';
@@ -92,5 +105,5 @@ export function pricingInfoToString(pricingInfo: ExtendedPricingInfo | null): st
92105
if (pricingInfo.pricingModel === ACTOR_PRICING_MODEL.PAY_PER_EVENT) {
93106
return payPerEventPricingToString(pricingInfo.pricingPerEvent);
94107
}
95-
return 'unknown';
108+
return 'Not available';
96109
}

0 commit comments

Comments
 (0)