Skip to content

Commit f1f6a90

Browse files
jirispilkaclaude
andauthored
feat: Adopt dedent for multiline tool descriptions (#609)
* feat: adopt dedent for multiline tool descriptions in pilot files Add `dedent` dependency and convert 3 pilot files to use `dedent` tagged template literals for long description strings: - src/tools/common/get_dataset_items.ts - src/tools/common/dataset_collection.ts - src/tools/common/get_actor_output.ts Add string formatting rules to CONTRIBUTING.md documenting the convention. Resolves #574 https://claude.ai/code/session_01PQP1ovrVPikt86BGPDecUt * feat: dedent formatting in Actor response --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5cdd2bb commit f1f6a90

7 files changed

Lines changed: 128 additions & 72 deletions

File tree

CONTRIBUTING.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,40 @@ Use comments to guide reviewers:
7878
* **Zod Validators:** Suffix with `Validator`.
7979
* **Text/Copy:** Use the branded term `Actor` (capitalized) instead of `actor` in user-facing texts, labels, notifications, error messages, etc.
8080

81+
* **String formatting:**
82+
* Use plain single-quoted strings for short one-liners.
83+
* Use `dedent` (tagged template literal) for any string that would otherwise exceed `max-len` or span multiple lines — including tool `description` fields, LLM instructions, and single-sentence strings that are simply long.
84+
* Inline `dedent` directly as a property or variable value — do not extract it to a named constant.
85+
* `dedent` introduces `\n` at each source line break. This is fine for LLM-facing strings (tool descriptions, instructions, notes), but avoid it for strings where whitespace is significant or where `\n` would break rendering (e.g. UI labels, log messages, URLs).
86+
* For strings where `\n` is not acceptable, use string concatenation (`+`) to split across lines for `max-len` compliance.
87+
```typescript
88+
import dedent from 'dedent';
89+
90+
// Multi-line prose — always use dedent
91+
export const toolEntry = {
92+
name: 'example-tool',
93+
description: dedent`
94+
Line 1.
95+
Line 2.
96+
97+
USAGE:
98+
- Example
99+
`,
100+
};
101+
102+
// Long single sentence going to LLM — dedent is fine, \n is ok
103+
const note = isLimited ? dedent`
104+
You only have a preview (${count} of ${total} items).
105+
Do not present this as the full output.
106+
` : '';
107+
108+
// Long string where \n is NOT ok (e.g. log message) — use + instead
109+
const msg = `Something failed for actor "${actorName}"`
110+
+ ` with status ${status}.`;
111+
```
112+
* Avoid `[].join('\n')` for multiline stringsit is noisy and harder to edit.
113+
* When migrating existing strings, keep the wording **semantically unchanged**.
114+
81115
* **Comments:**
82116
* Use proper English (spelling, grammar, punctuation, capitalization).
83117
* Use JSDoc `/**` for documentation, `//` for generic comments, and avoid `/*` (single asterix multiline comments).

package-lock.json

Lines changed: 15 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"algoliasearch": "^5.31.0",
5252
"apify": "^3.4.2",
5353
"apify-client": "^2.22.1",
54+
"dedent": "^1.7.2",
5455
"dotenv": "^16.4.7",
5556
"express": "^4.21.2",
5657
"mcp-client-capabilities": "^0.0.5",

src/tools/common/dataset_collection.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dedent from 'dedent';
12
import { z } from 'zod';
23

34
import { ApifyClient } from '../../apify_client.js';
@@ -27,18 +28,19 @@ const getUserDatasetsListArgs = z.object({
2728
export const getUserDatasetsList: ToolEntry = Object.freeze({
2829
type: 'internal',
2930
name: HelperTools.DATASET_LIST_GET,
30-
description: `List datasets (collections of Actor run data) for the authenticated user.
31-
Actor runs automatically produce unnamed datasets (set unnamed=true to include them). Users can also create named datasets.
31+
description: dedent`
32+
List datasets (collections of Actor run data) for the authenticated user.
33+
Actor runs automatically produce unnamed datasets (set unnamed=true to include them). Users can also create named datasets.
3234
33-
The results will include datasets with itemCount, access settings, and usage stats, sorted by createdAt (ascending by default).
34-
Use limit (max 20), offset, and desc to paginate and sort.
35+
The results will include datasets with itemCount, access settings, and usage stats, sorted by createdAt (ascending by default).
36+
Use limit (max 20), offset, and desc to paginate and sort.
3537
36-
USAGE:
37-
- Use when you need to browse available datasets (named or unnamed) to locate data.
38+
USAGE:
39+
- Use when you need to browse available datasets (named or unnamed) to locate data.
3840
39-
USAGE EXAMPLES:
40-
- user_input: List my last 10 datasets (newest first)
41-
- user_input: List unnamed datasets`,
41+
USAGE EXAMPLES:
42+
- user_input: List my last 10 datasets (newest first)
43+
- user_input: List unnamed datasets`,
4244
inputSchema: z.toJSONSchema(getUserDatasetsListArgs) as ToolInputSchema,
4345
ajvValidate: compileSchema(z.toJSONSchema(getUserDatasetsListArgs)),
4446
annotations: {

src/tools/common/get_actor_output.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dedent from 'dedent';
12
import { z } from 'zod';
23

34
import { createApifyClientWithSkyfireSupport } from '../../apify_client.js';
@@ -67,23 +68,24 @@ export function cleanEmptyProperties(obj: unknown): unknown {
6768
export const getActorOutput: ToolEntry = Object.freeze({
6869
type: 'internal',
6970
name: HelperTools.ACTOR_OUTPUT_GET,
70-
description: `Retrieve the output dataset items of a specific Actor run using its datasetId.
71-
You can select specific fields to return (supports dot notation like "crawl.statusCode") and paginate results with offset and limit.
72-
This tool is a simplified version of the get-dataset-items tool, focused on Actor run outputs.
71+
description: dedent`
72+
Retrieve the output dataset items of a specific Actor run using its datasetId.
73+
You can select specific fields to return (supports dot notation like "crawl.statusCode") and paginate results with offset and limit.
74+
This tool is a simplified version of the get-dataset-items tool, focused on Actor run outputs.
7375
74-
The results will include the dataset items from the specified dataset. If you provide fields, only those fields will be included (nested fields supported via dot notation).
76+
The results will include the dataset items from the specified dataset. If you provide fields, only those fields will be included (nested fields supported via dot notation).
7577
76-
You can obtain the datasetId from an Actor run (e.g., after calling an Actor with the call-actor tool) or from the Apify Console (Runs → Run details → Dataset ID).
78+
You can obtain the datasetId from an Actor run (e.g., after calling an Actor with the call-actor tool) or from the Apify Console (Runs → Run details → Dataset ID).
7779
78-
USAGE:
79-
- Use when you need to read Actor output data (full items or selected fields), especially when preview does not include all fields.
80+
USAGE:
81+
- Use when you need to read Actor output data (full items or selected fields), especially when preview does not include all fields.
8082
81-
USAGE EXAMPLES:
82-
- user_input: Get data of my last Actor run
83-
- user_input: Get number_of_likes from my dataset
84-
- user_input: Return only crawl.statusCode and url from dataset aab123
83+
USAGE EXAMPLES:
84+
- user_input: Get data of my last Actor run
85+
- user_input: Get number_of_likes from my dataset
86+
- user_input: Return only crawl.statusCode and url from dataset aab123
8587
86-
Note: This tool is automatically included if the Apify MCP Server is configured with any Actor tools (e.g., "apify-slash-rag-web-browser") or tools that can interact with Actors (e.g., "call-actor", "add-actor").`,
88+
Note: This tool is automatically included if the Apify MCP Server is configured with any Actor tools (e.g., "apify-slash-rag-web-browser") or tools that can interact with Actors (e.g., "call-actor", "add-actor").`,
8789
inputSchema: z.toJSONSchema(getActorOutputArgs) as ToolInputSchema,
8890
outputSchema: datasetItemsOutputSchema,
8991
/**

src/tools/common/get_dataset_items.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dedent from 'dedent';
12
import { z } from 'zod';
23

34
import { createApifyClientWithSkyfireSupport } from '../../apify_client.js';
@@ -38,18 +39,19 @@ const getDatasetItemsArgs = z.object({
3839
export const getDatasetItems: ToolEntry = Object.freeze({
3940
type: 'internal',
4041
name: HelperTools.DATASET_GET_ITEMS,
41-
description: `Retrieve dataset items with pagination, sorting, and field selection.
42-
Use clean=true to skip empty items and hidden fields. Include or omit fields using comma-separated lists.
43-
For nested objects, first flatten them (e.g., flatten="metadata"), then reference nested fields via dot notation (e.g., fields="metadata.url").
42+
description: dedent`
43+
Retrieve dataset items with pagination, sorting, and field selection.
44+
Use clean=true to skip empty items and hidden fields. Include or omit fields using comma-separated lists.
45+
For nested objects, first flatten them (e.g., flatten="metadata"), then reference nested fields via dot notation (e.g., fields="metadata.url").
4446
45-
The results will include items along with pagination info (limit, offset) and total count.
47+
The results will include items along with pagination info (limit, offset) and total count.
4648
47-
USAGE:
48-
- Use when you need to read data from a dataset (all items or only selected fields).
49+
USAGE:
50+
- Use when you need to read data from a dataset (all items or only selected fields).
4951
50-
USAGE EXAMPLES:
51-
- user_input: Get first 100 items from dataset abd123
52-
- user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`,
52+
USAGE EXAMPLES:
53+
- user_input: Get first 100 items from dataset abd123
54+
- user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`,
5355
inputSchema: z.toJSONSchema(getDatasetItemsArgs) as ToolInputSchema,
5456
outputSchema: datasetItemsOutputSchema,
5557
/**

0 commit comments

Comments
 (0)