n8n-nodes-autotask 2.16.1 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/README.md +112 -202
  2. package/dist/nodes/Autotask/AutotaskAiTools.node.js +1 -1
  3. package/dist/nodes/Autotask/ai-tools/description-builders.d.ts.map +1 -1
  4. package/dist/nodes/Autotask/ai-tools/description-builders.js +15 -51
  5. package/dist/nodes/Autotask/ai-tools/description-builders.js.map +1 -1
  6. package/dist/nodes/Autotask/ai-tools/error-formatter.d.ts +1 -0
  7. package/dist/nodes/Autotask/ai-tools/error-formatter.d.ts.map +1 -1
  8. package/dist/nodes/Autotask/ai-tools/error-formatter.js +1 -0
  9. package/dist/nodes/Autotask/ai-tools/error-formatter.js.map +1 -1
  10. package/dist/nodes/Autotask/ai-tools/operation-handlers/ticket-convenience.d.ts.map +1 -1
  11. package/dist/nodes/Autotask/ai-tools/operation-handlers/ticket-convenience.js +24 -16
  12. package/dist/nodes/Autotask/ai-tools/operation-handlers/ticket-convenience.js.map +1 -1
  13. package/dist/nodes/Autotask/ai-tools/schema-generator.js +7 -7
  14. package/dist/nodes/Autotask/ai-tools/schema-generator.js.map +1 -1
  15. package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.d.ts +21 -0
  16. package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.d.ts.map +1 -1
  17. package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.js +37 -0
  18. package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.js.map +1 -1
  19. package/dist/nodes/Autotask/ai-tools/tool-executor.d.ts.map +1 -1
  20. package/dist/nodes/Autotask/ai-tools/tool-executor.js +16 -1
  21. package/dist/nodes/Autotask/ai-tools/tool-executor.js.map +1 -1
  22. package/dist/package.json +11 -1
  23. package/dist/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +11 -1
package/README.md CHANGED
@@ -297,133 +297,76 @@ This node is optimised for AI agents and tool-calling systems with specialised f
297
297
 
298
298
  #### Quick Start for AI Agents
299
299
 
300
- **1. Introspect Resources**
301
- ```javascript
302
- // Discover available fields and requirements
303
- operation: aiHelper.describeResource
304
- params: { resource: "ticket", mode: "write" }
305
- ```
300
+ The recommended path is the **Autotask AI Tools** node (see the [Autotask AI Tools](#autotask-ai-tools) section above). Add one node per resource, connect each to your AI Agent's `Tools` input, and the agent gets a tool named `autotask_<resource>` with a unified `operation` enum.
306
301
 
307
- **2. Prepare Data**
308
- ```javascript
309
- // Use JSON parameters for direct data input
310
- bodyJson: {
311
- "title": "API Integration Issue",
312
- "description": "Customer reporting connection problems",
313
- "priority": "Medium",
314
- "status": "New"
315
- }
316
- ```
302
+ **1. Build the request**
317
303
 
318
- Note: You may provide labels for picklist/reference fields in `bodyJson` (e.g., `status: "New"`). They are automatically resolved to IDs pre-flight.
304
+ The agent calls a tool like this (the LLM emits the JSON; you don't write it manually):
319
305
 
320
- **3. Preview First (Optional)**
321
- ```javascript
322
- // Test your request without making API calls
323
- dryRun: true
306
+ ```jsonc
307
+ autotask_ticket({
308
+ operation: "create",
309
+ title: "API Integration Issue",
310
+ description: "Customer reporting connection problems",
311
+ priority: "Medium", // human-readable label — resolved automatically
312
+ status: "New", // human-readable label — resolved automatically
313
+ companyID: "Tech Solutions" // reference label — resolved automatically
314
+ })
324
315
  ```
325
316
 
326
- **4. Execute with Optimal Output**
327
- ```javascript
328
- // Choose output format for token efficiency
329
- outputMode: "rawIds" // Most efficient
330
- outputMode: "idsAndLabels" // Default (balanced)
331
- outputMode: "labelsOnly" // Most readable
332
- ```
317
+ Labels for picklist and reference fields are resolved to numeric IDs before the API call. Successful responses include `resolvedLabels` showing each mapping. Ambiguous matches produce `pendingConfirmations` for user confirmation rather than guessing.
333
318
 
334
- #### AI Helper Operations
319
+ **2. Inspect when needed**
335
320
 
336
- **Introspection Endpoint:**
337
- - `aiHelper.describeResource(resource, mode)` - Get field metadata, requirements, constraints, and **entity dependencies**
338
- - `aiHelper.listPicklistValues(resource, fieldId, query, limit, page)` - Get valid values for dropdown fields
339
- - `aiHelper.validateParameters(resource, mode, fieldValues)` - Validate field values without API calls (pre-flight validation)
321
+ Every AI Tools node instance also exposes three helper operations automatically:
340
322
 
341
- **Resource and Time Entry:**
342
- - `resource.whoAmI` - Resolve the current authenticated API user (use before user-scoped actions)
343
- - `timeEntry.getPosted` / `timeEntry.getUnposted` - List time entries by posting status (with optional filters)
323
+ - `describeFields` field metadata (types, required, picklist/reference, dependencies)
324
+ - `listPicklistValues` valid values for a picklist field
325
+ - `describeOperation` full documentation for one operation on the tool
344
326
 
345
- **Dynamic Dependency Discovery:**
346
- - **Reference fields** show what entity they link to (e.g., `companyID → company`)
347
- - **Field dependencies** reveal required relationships (e.g., `contactID requires: companyID`)
348
- - **Workflow guidance** provides creation order tips (e.g., "Ensure company exists before creating contact")
327
+ The agent will usually only need these on edge cases — most write operations embed a compact required-fields summary directly in their description.
349
328
 
350
- **Enhanced Validation:**
351
- - **JSON Schema validation** - Immediate feedback on malformed `bodyJson`/`selectColumnsJson`
352
- - **Parameter pre-validation** - Validate field values, types, dependencies without API calls
353
- - **Structured error responses** - Detailed validation results with field-by-field feedback
329
+ **3. Read the response**
354
330
 
355
- **JSON Parameter Fallbacks:**
356
- - `bodyJson` - Override UI mappings for write operations (create/update)
357
- - `selectColumnsJson` - Specify fields for read operations as JSON array
331
+ Responses use a flat shape — the top-level key tells you the response type: `records[]` (list), `record{}` (item), `id` + `record{}` (mutation), `matchCount` (count), `outcome` (compound). All responses include a plain-English `summary` field.
358
332
 
359
- **Agent-Friendly Features:**
360
- - `outputMode` - Control response format (rawIds/idsAndLabels/labelsOnly)
361
- - `dryRun` - Get request preview without API execution
362
- - Smart error hints with actionable suggestions
333
+ **4. Recover from errors**
363
334
 
364
- #### Tool Configuration for Maximum Effectiveness
335
+ Error responses include `errorType`, a `summary` prefixed with `REQUIRED NEXT STEP: ...` for actionable cases, and a `nextAction` string telling the agent what to call before retrying (e.g. `listPicklistValues`, `describeFields`).
365
336
 
366
- For optimal AI agent integration, configure multiple instances of this node as separate tools. This provides focused, reliable access to different resource types.
337
+ > **Legacy path:** The main **Autotask** node also exposes a deprecated `aiHelper` resource (`describeResource`, `listPicklistValues`, `validateParameters`) and per-operation flags like `bodyJson`, `selectColumnsJson`, `dryRun`, `outputMode`. These remain in place for existing workflows but should not be used for new AI agent integrations — use the AI Tools node instead.
367
338
 
368
- **Recommended Tool Setup:**
339
+ #### Tool Configuration for Maximum Effectiveness
369
340
 
370
- ```javascript
371
- // Tool 1: Resource Discovery and Field Introspection
372
- {
373
- name: "autotask_inspector",
374
- description: "Discover Autotask resources, fields, and valid values",
375
- resource: "aiHelper",
376
- operations: ["describeResource", "listPicklistValues", "validateParameters"]
377
- }
341
+ For optimal AI agent integration, add **one Autotask AI Tools node per resource** to your workflow and connect each one to the AI Agent's `Tools` input. Every instance becomes a single unified tool named `autotask_<resource>` (e.g. `autotask_contact`, `autotask_company`) with an `operation` enum the LLM selects at call time.
378
342
 
379
- // Tool 2: Contact Management
380
- {
381
- name: "autotask_contacts",
382
- description: "Read and write Autotask contacts and people",
383
- resource: "contact",
384
- operations: ["get", "getMany", "create", "update"],
385
- defaultParams: {
386
- outputMode: "idsAndLabels",
387
- selectColumnsJson: ["id", "firstName", "lastName", "emailAddress", "companyID", "title", "phone"]
388
- }
389
- // Accepts labels in bodyJson; labels are auto-resolved to IDs
390
- }
343
+ **How to add a tool (n8n UI):**
391
344
 
392
- // Tool 3: Company/Account Management
393
- {
394
- name: "autotask_companies",
395
- description: "Read and write Autotask companies and accounts",
396
- resource: "company",
397
- operations: ["get", "getMany", "create", "update"],
398
- defaultParams: {
399
- outputMode: "idsAndLabels",
400
- selectColumnsJson: ["id", "companyName", "companyType", "phone", "address1", "city", "state"]
401
- }
402
- // Accepts labels in bodyJson; labels are auto-resolved to IDs
403
- }
345
+ 1. Drag an **Autotask AI Tools** node onto the canvas.
346
+ 2. Connect its `Tools` output to the `Tools` input of your AI Agent node.
347
+ 3. Configure the node:
348
+ - **Resource Name or ID** pick one resource (e.g. `contact`).
349
+ - **Operations Names or IDs** — multi-select the operations you want the agent to use (e.g. `get`, `getMany`, `count`). Helper operations `describeFields`, `listPicklistValues`, and `describeOperation` are always included automatically — no need to expose them as a separate inspector tool.
350
+ - **Allow Write Operations** — toggle on to expose `create`, `createIfNotExists`, `update`, `delete`, and resource-specific mutations. Default is off (read-only).
351
+ - **Tool Description Appendix** — optional free-text appended to the tool description, visible to the LLM. Use this for deployment-specific guardrails (e.g. *"Only query tickets in the MSP support queue. Never create tickets for internal IT."*).
352
+ - **Time Entry Notes Guidance** — appears only when Resource = Time Entry. Use it to enforce your house style for Summary Notes and Internal Notes.
353
+ 4. Repeat for each resource you want the agent to access. Common starting set:
404
354
 
405
- // Tool 4: General Resource Access
406
- {
407
- name: "autotask_resources",
408
- description: "Access any Autotask resource with full flexibility",
409
- allResources: true,
410
- defaultParams: {
411
- outputMode: "rawIds" // Most token-efficient for exploratory queries
412
- }
413
- // Accepts labels in bodyJson; labels are auto-resolved to IDs
414
- }
415
- ```
355
+ | Node instance | Resource | Typical operations | Write enabled |
356
+ |---|---|---|---|
357
+ | Companies | `company` | `get`, `getMany`, `count`, `searchByDomain` | usually off |
358
+ | Contacts | `contact` | `get`, `getMany`, `create`, `update` | as needed |
359
+ | Tickets | `ticket` | `get`, `getMany`, `count`, `create`, `update`, `slaHealthCheck`, `summary` | as needed |
360
+ | Time entries | `timeEntry` | `getPosted`, `getUnposted`, `create`, `createIfNotExists` | as needed |
361
+ | Resources (MSP staff) | `resource` | `getMany`, `whoAmI` | off |
416
362
 
417
- **Usage Pattern:**
418
- 1. **Start with Inspector** - Use `autotask_inspector` to understand field requirements
419
- 2. **Use Focused Tools** - Call `autotask_contacts` or `autotask_companies` for CRM related operations
420
- 3. **Use Specialist Tools** - Use `autotask_resources` for lookups of Autotask MSP staff (resources)
363
+ **Benefits of one-node-per-resource:**
364
+ - **Focused schemas** the LLM sees a tight, predictable set of operations per tool.
365
+ - **Granular write control** enable writes on `contact` without enabling them on `ticket`.
366
+ - **Per-resource deployment context** different appendix guidance for each resource.
367
+ - **Cleaner execution view** — each tool call is labelled by resource in n8n's log.
421
368
 
422
- **Benefits:**
423
- - **Faster execution** - Pre-configured tools reduce parameter complexity
424
- - **Better reliability** - Focused tools have predictable schemas
425
- - **Token efficiency** - Default parameters optimised for each use case
426
- - **Easier debugging** - Clear separation of concerns
369
+ **Label resolution is automatic.** When the LLM passes a human-readable name to a picklist or reference field (e.g. `resourceID: "Will Spence"` or `status: "New"`), it's resolved to the numeric ID before the API call. Ambiguous matches return `pendingConfirmations` rather than guessing. No pre-configuration needed.
427
370
 
428
371
  #### Environment Setup
429
372
 
@@ -441,123 +384,90 @@ Configuration options:
441
384
 
442
385
  #### Example Agent Workflow
443
386
 
444
- **Scenario: Create a contact for a new company**
387
+ **Scenario: Create a contact at an existing company**
445
388
 
446
- ```javascript
447
- // 1. Inspect contact requirements using dedicated tool
448
- autotask_inspector.call({
449
- operation: "describeResource",
450
- targetResource: "contact",
451
- mode: "write"
452
- })
453
- // Returns: {
454
- // fields: [
455
- // { id: "companyID", required: true, isReference: true, referencesEntity: "company" },
456
- // { id: "firstName", required: true, type: "string" },
457
- // { id: "lastName", required: true, type: "string" }
458
- // ],
459
- // notes: [
460
- // "Required fields for write: companyID, firstName, lastName",
461
- // "Reference fields (must reference existing entities): companyID → company",
462
- // "Workflow tip: Ensure referenced company exists before creating contact."
463
- // ]
464
- // }
465
-
466
- // 2. Check company picklist values if needed
467
- autotask_inspector.call({
468
- operation: "listPicklistValues",
469
- targetResource: "contact",
470
- fieldId: "companyID",
471
- query: "Tech Solutions" // Search for company
472
- })
389
+ This is illustrative — the LLM picks the tool name and `operation` value, and supplies arguments matching each tool's auto-generated Zod schema. You don't write any of this code; it shows what the agent sees and does at runtime.
473
390
 
474
- // 2.5. Validate parameters before creation (NEW!)
475
- autotask_inspector.call({
476
- operation: "validateParameters",
477
- targetResource: "contact",
478
- mode: "create",
479
- fieldValues: {
480
- "firstName": "John",
481
- "lastName": "Smith",
482
- "emailAddress": "john.smith@techsolutions.com",
483
- "companyID": 12345,
484
- "title": "IT Manager"
485
- }
486
- })
487
- // Returns: {
488
- // isValid: true,
489
- // errors: [],
490
- // warnings: [
491
- // { field: "companyID", message: "Reference field 'companyID' points to company. Ensure the referenced record exists.", code: "REFERENCE_EXISTENCE_CHECK" }
492
- // ],
493
- // summary: { totalFields: 15, providedFields: 5, validFields: 5, requiredFieldsMissing: 0, invalidValues: 0 }
494
- // }
495
-
496
- // 3. Create contact using focused tool
497
- autotask_contacts.call({
498
- operation: "create",
499
- bodyJson: {
500
- "firstName": "John",
501
- "lastName": "Smith",
502
- "emailAddress": "john.smith@techsolutions.com",
503
- "companyID": 12345,
504
- "title": "IT Manager"
505
- },
506
- dryRun: true // Preview first
391
+ ```jsonc
392
+ // Assumes the workflow has two AI Tools node instances configured:
393
+ // - Resource = company → exposed as tool autotask_company
394
+ // - Resource = contact → exposed as tool autotask_contact (Allow Write Operations = on)
395
+
396
+ // 1. Find the company by name. Helper operation describeFields is always available
397
+ // if the agent needs to inspect the schema first — usually it doesn't, because
398
+ // required-field summaries are embedded in each create operation's description.
399
+ autotask_company({
400
+ operation: "getMany",
401
+ filter_field: "companyName",
402
+ filter_op: "contains",
403
+ filter_value: "Tech Solutions"
507
404
  })
508
- // Dry-run response includes a `resolutions` array when labels were resolved to IDs, e.g.:
509
- // resolutions: [{ field: 'status', from: 'New', to: 1, method: 'picklist' }]
405
+ // { records: [{ id: 12345, companyName: "Tech Solutions Ltd", ... }], summary: "..." }
510
406
 
511
- // 4. Execute after validation
512
- autotask_contacts.call({
407
+ // 2. Create the contact. Picklist and reference fields accept human-readable labels;
408
+ // they are resolved to numeric IDs automatically.
409
+ autotask_contact({
513
410
  operation: "create",
514
- bodyJson: { /* same data */ },
515
- outputMode: "idsAndLabels"
411
+ firstName: "John",
412
+ lastName: "Smith",
413
+ emailAddress: "john.smith@techsolutions.com",
414
+ companyID: 12345, // numeric ID returned in step 1
415
+ title: "IT Manager"
516
416
  })
417
+ // → { id: 67890, record: { ... }, resolvedLabels: [], summary: "Created contact 67890" }
517
418
 
518
- // 5. Retrieve company details using focused tool
519
- autotask_companies.call({
520
- operation: "get",
521
- id: 12345
522
- })
419
+ // 3. If the LLM had passed companyID: "Tech Solutions Ltd" instead of 12345, the
420
+ // response would include resolvedLabels showing the name→ID mapping. Ambiguous
421
+ // names produce pendingConfirmations rather than guessing.
523
422
  ```
524
423
 
424
+ **Auto-included helper operations** (no configuration required, available on every AI Tools node instance):
425
+
426
+ - `describeFields` — return field metadata for the resource (types, required, picklist/reference)
427
+ - `listPicklistValues` — return valid values for a picklist field
428
+ - `describeOperation` — return full documentation for a specific operation on the tool
429
+
525
430
  #### Error Self-Healing
526
431
 
527
- Errors include structured hints to help agents self-correct:
432
+ Errors return a flat JSON shape with structured fields the agent can act on directly:
528
433
 
529
- ```javascript
530
- // Error response includes actionable guidance
434
+ ```jsonc
531
435
  {
532
- "error": "Field 'priority' has invalid value 'Urgent'",
533
- "extensions": {
534
- "hint": "Use aiHelper.listPicklistValues('ticket', 'priority') to get valid options, then retry with a valid value.",
535
- "suggestions": [
536
- "Get valid values: aiHelper.listPicklistValues('ticket', 'priority')",
537
- "Use exact values from the picklist response"
538
- ]
539
- }
436
+ "error": true,
437
+ "errorType": "INVALID_PICKLIST_VALUE",
438
+ "resource": "ticket",
439
+ "operation": "create",
440
+ "summary": "REQUIRED NEXT STEP: Call autotask_ticket with operation 'listPicklistValues' for field 'priority', then retry — Field 'priority' rejected value 'Urgent'",
441
+ "nextAction": "Call autotask_ticket with operation 'listPicklistValues' for field 'priority', then retry",
442
+ "mustRetryAfter": ["listPicklistValues"],
443
+ "invalidField": "priority",
444
+ "invalidValue": "Urgent"
540
445
  }
541
446
  ```
542
447
 
448
+ Key fields:
449
+ - `errorType` — stable string constant (e.g. `INVALID_PICKLIST_VALUE`, `ENTITY_NOT_FOUND`, `MISSING_REQUIRED_FIELDS`, `WRITE_OPERATION_BLOCKED`). Use this to branch in agent prompts or downstream logic.
450
+ - `summary` — human-readable. Actionable errors are prefixed with `"REQUIRED NEXT STEP: ..."` so the recovery step is visible in the instruction register, not just buried in context.
451
+ - `nextAction` — exact recovery step in plain English. References the unified tool name (e.g. `autotask_ticket with operation 'listPicklistValues'`).
452
+ - `mustRetryAfter` — optional list of operations the agent must call before retrying. Surfaced by `formatFieldError`, `formatRequiredFieldsError`, `formatNotFoundError`, and picklist-related failures.
453
+ - Context fields (`invalidField`, `filtersUsed`, `missingFields`, `pendingConfirmations`, etc.) appear at the **root** of the response — no `context` wrapper.
454
+
543
455
  #### Best Practices for Agents
544
456
 
545
- - **Configure focused tools** - Set up separate tools for inspector, contacts, companies, and general resources
546
- - **Start with inspection** - Always call `autotask_inspector.describeResource` first to understand field requirements
547
- - **Use focused tools** - Prefer `autotask_contacts` or `autotask_companies` over general tools for better reliability
548
- - **Validate before execution** - Use `autotask_inspector.validateParameters` for pre-flight validation to catch errors early
549
- - **Optimise responses** - Use `selectColumnsJson` to reduce payload size and `outputMode: "rawIds"` for token efficiency
550
- - **Double-check with dry-run** - Use `dryRun: true` to preview requests before execution, especially for write operations
551
- - **Handle errors smartly** - Follow the structured hints in error responses for self-correction
552
- - **Cache discoveries** - Store field metadata and picklist values to avoid repeated introspection calls
553
- - **JSON validation** - Invalid JSON in `bodyJson`/`selectColumnsJson` is caught immediately with helpful error messages
457
+ - **One node per resource** gives the agent named, focused tools (`autotask_company`, `autotask_ticket`, etc.) with predictable schemas.
458
+ - **Read-only by default** leave **Allow Write Operations** off unless the agent genuinely needs to mutate data. Enable per-resource, not globally.
459
+ - **Use the appendix for guardrails** — put deployment-specific constraints in **Tool Description Appendix** so they're visible to the LLM on every call.
460
+ - **Trust label resolution** let the LLM pass names like `"Will Spence"` or `"In Progress"`. Resolution is automatic, transparent (`resolvedLabels` in the response), and refuses to guess on ambiguous matches.
461
+ - **Follow error `nextAction`** — error responses include a `nextAction` string the agent should execute before retrying (e.g. *call `describeFields`*, *call `listPicklistValues`*). Actionable error types prefix the summary with `"REQUIRED NEXT STEP: ..."`.
462
+ - **Use `count` for sanity checks** when listing tickets/charges/etc., call `count` first if the agent only needs a total. Cheaper than `getMany`.
463
+ - **Use `createIfNotExists`** for idempotent operations supported on charges, configuration items, contracts, contract services, change request links, and time entries. Configurable `dedupFields` decide what counts as a duplicate.
554
464
 
555
465
  #### Troubleshooting
556
466
 
557
- **Tool Not Available:** Ensure `N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true` is set
558
- **No Parameters Visible:** Call `aiHelper.describeResource` to inspect available fields
559
- **Large Responses:** Use `selectColumnsJson` and `outputMode: "rawIds"` for efficiency
560
- **Validation Errors:** Follow error hints to resolve field requirement issues
467
+ **Tool Not Available:** Ensure `N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true` is set in your n8n environment.
468
+ **Agent doesn't see a write operation:** Toggle **Allow Write Operations** on the corresponding AI Tools node, then save and re-execute.
469
+ **LLM passes the wrong picklist value:** The response will include `pendingConfirmations` for ambiguous labels. The agent should surface the candidates to the user or call `listPicklistValues` to disambiguate.
470
+ **Large responses overflowing the agent's context:** Reduce `limit`, narrow with `filter_field`/`filter_op`/`filter_value`, or use `count` first to gauge result size before fetching.
561
471
 
562
472
  ## Usage
563
473
 
@@ -386,7 +386,7 @@ class AutotaskAiTools {
386
386
  const withGuidance = timeEntryNotesGuidance
387
387
  ? `${withAppendix}\n\nTIME ENTRY NOTES GUIDANCE:\n${timeEntryNotesGuidance}`
388
388
  : withAppendix;
389
- const DESCRIPTION_HARD_LIMIT = 2400;
389
+ const DESCRIPTION_HARD_LIMIT = 1300;
390
390
  let description = withGuidance;
391
391
  if (description.length > DESCRIPTION_HARD_LIMIT) {
392
392
  const originalLength = description.length;
@@ -1 +1 @@
1
- {"version":3,"file":"description-builders.d.ts","sourceRoot":"","sources":["../../../../nodes/Autotask/ai-tools/description-builders.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"description-builders.d.ts","sourceRoot":"","sources":["../../../../nodes/Autotask/ai-tools/description-builders.ts"],"names":[],"mappings":"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"}
@@ -72,11 +72,8 @@ const RESOURCE_LANGUAGE_CONFIG = {
72
72
  };
73
73
  function buildToolContractBlock() {
74
74
  return [
75
- 'CAPABILITIES: filter, count, paging only. NO groupBy, aggregation, or server-side sort. ' +
76
- 'No cross-entity joins inside one call EXCEPT via documented convenience operations (e.g. ticket.getByResource handles primary+secondary lookups, ticket.searchByKeyword spans tickets/notes/time entries). ' +
77
- 'For other cross-entity lookups, do a two-step: query the join/child entity first, collect IDs, then query the parent with filter_op=in. ' +
78
- 'For breakdowns: ask user for ≤10 IDs, then run one count per ID.',
79
- 'ERRORS: when response has "error":true, the "nextAction" field is a directive TO YOU — execute it on your next call before responding. Never retry the same failed call unchanged.',
75
+ 'CAPABILITIES: filter/count/paging only. No groupBy/aggregation/server-side sort. Cross-entity lookups need two steps (child first → parent with filter_op=in), except documented convenience ops.',
76
+ 'ERRORS: when "error":true, the "nextAction" field is a directive execute it before retrying. Never retry an unchanged failed call.',
80
77
  ].join('\n');
81
78
  }
82
79
  const DESCRIPTION_TEMPLATE_CACHE_MAX = 600;
@@ -460,12 +457,6 @@ function buildResourceTransferOwnershipDescription(resourceName) {
460
457
  'By default, only open/active-style work is targeted by excluding terminal statuses. ' +
461
458
  `If field names or expected behaviour are uncertain, call autotask_${resourceName} with operation 'describeFields' first.`);
462
459
  }
463
- function buildCreateIfNotExistsDescription(resource) {
464
- var _a;
465
- const extraHint = (_a = resource_language_1.RESOURCE_EXTRA_HINTS[resource]) !== null && _a !== void 0 ? _a : '';
466
- return `Idempotent create for ${resource} using dedupFields (array of API field names); optional updateFields for upsert; errorOnDuplicate (default false). Pass same fields as create. Outcomes: created, skipped, updated.` +
467
- (extraHint ? ` ${extraHint}` : '');
468
- }
469
460
  function buildDescribeFieldsDescription(resourceLabel) {
470
461
  return (`Describe available ${resourceLabel} fields for AI usage. ` +
471
462
  `Use mode 'read' for query fields and mode 'write' for create/update fields.`);
@@ -481,7 +472,7 @@ const TRUNCATION_SUFFIX = "...[description truncated — call with operation='de
481
472
  * Cuts at the last word boundary before the limit and appends a visible truncation suffix
482
473
  * so the LLM knows content was removed.
483
474
  */
484
- function truncateDescription(text, limit = 2000) {
475
+ function truncateDescription(text, limit = 1300) {
485
476
  if (text.length <= limit)
486
477
  return text;
487
478
  const cutAt = Math.max(0, limit - TRUNCATION_SUFFIX.length);
@@ -497,7 +488,7 @@ function injectDescriptionReferenceUtc(template, referenceUtc) {
497
488
  return template.split(exports.DESCRIPTION_REFERENCE_PLACEHOLDER).join(referenceUtc);
498
489
  }
499
490
  function buildUnifiedDescriptionTemplate(resourceLabel, resource, operations, readFields, writeFields, supportsImpersonation) {
500
- var _a, _b, _c, _d;
491
+ var _a;
501
492
  const cacheKey = getDescriptionTemplateCacheKey(resource, operations, readFields, writeFields, supportsImpersonation);
502
493
  const cached = descriptionTemplateCache.get(cacheKey);
503
494
  if (cached) {
@@ -518,9 +509,9 @@ function buildUnifiedDescriptionTemplate(resourceLabel, resource, operations, re
518
509
  ...new Set([...operations, 'describeFields', 'listPicklistValues', 'describeOperation']),
519
510
  ];
520
511
  const sections = [];
521
- // Tool contract block — always first, guaranteed to survive truncation
512
+ // Tool contract block — always first, guaranteed to survive truncation.
522
513
  sections.push(buildToolContractBlock());
523
- // Safety-critical header — always present for write ops
514
+ // Safety-critical header — always present for write ops.
524
515
  if (hasWriteOps) {
525
516
  sections.push('WRITE SAFETY: name/reference resolutions must match exactly. Ambiguous or failed resolutions block writes.');
526
517
  }
@@ -533,44 +524,17 @@ function buildUnifiedDescriptionTemplate(resourceLabel, resource, operations, re
533
524
  sections.push(identityHint);
534
525
  }
535
526
  if (resource === 'company') {
536
- sections.push('Company identifier priority rule: derive domain from email/website first; only fall back to companyName contains matching when no domain signal is available.');
527
+ sections.push("Company identifier priority: domain from email/website first; fall back to companyName contains only when no domain signal.");
537
528
  }
538
- sections.push(`Operations: ${allOps.join(', ')}. Set 'operation' to one.`, dateTimeReferenceSnippet(exports.DESCRIPTION_REFERENCE_PLACEHOLDER));
539
- sections.push(`operation 'describeFields': field metadata. Param: mode='read'|'write'.`);
540
- sections.push(`operation 'listPicklistValues': picklist values. Param: fieldId (NOT targetOperation).`);
541
- sections.push(`operation 'describeOperation': full docs for an op. Param: targetOperation.`);
529
+ // Operations list single canonical source of which ops this tool exposes.
530
+ sections.push(`Operations: ${allOps.join(', ')}. Set 'operation' to one.`);
531
+ sections.push(dateTimeReferenceSnippet(exports.DESCRIPTION_REFERENCE_PLACEHOLDER));
532
+ // Helper ops compressed into one line — full per-op detail lives in describeOperation.
533
+ sections.push("For op-specific docs (required fields, params, semantics) call 'describeOperation' (param: targetOperation). " +
534
+ "For field metadata call 'describeFields' (param: mode='read'|'write'). " +
535
+ "For picklist values call 'listPicklistValues' (param: fieldId).");
542
536
  if (supportsImpersonation) {
543
- sections.push(`Impersonation supported: pass 'impersonationResourceId' for write attribution.`);
544
- }
545
- for (const op of operations) {
546
- const metadata = (0, operation_metadata_1.getOperationMetadata)(op);
547
- let summary = metadata
548
- ? `operation '${op}': ${metadata.docsFragment}`
549
- : `operation '${op}': Perform ${op} on ${resourceLabel}.`;
550
- if (op === 'whoAmI') {
551
- summary = `operation '${op}': Resolve the authenticated ${resourceLabel} record.`;
552
- }
553
- else if (op === 'create') {
554
- const idempotentNote = operations.includes('createIfNotExists')
555
- ? " Prefer 'createIfNotExists' for agent workflows — idempotent and retry-safe."
556
- : '';
557
- summary = `operation '${op}': ${(_b = metadata === null || metadata === void 0 ? void 0 : metadata.docsFragment) !== null && _b !== void 0 ? _b : 'Create a new record.'} ${buildRequiredFieldsSummary(writeFields)}${idempotentNote}`;
558
- }
559
- else if (op === 'update') {
560
- if (resource === 'resourceTimeOffAdditional') {
561
- summary = `operation '${op}': Update time-off additional quotas for a resource. Provide 'resourceID' (name or numeric ID, auto-resolved) and the fields to change (annual/additional hours per category).`;
562
- }
563
- else {
564
- summary = `operation '${op}': ${(_c = metadata === null || metadata === void 0 ? void 0 : metadata.docsFragment) !== null && _c !== void 0 ? _c : "Update a record by numeric 'id'."}`;
565
- }
566
- }
567
- else if (op === 'createIfNotExists') {
568
- summary = `operation '${op}': ${buildCreateIfNotExistsDescription(resource)}`;
569
- }
570
- else if (op === 'getMany') {
571
- summary = `operation '${op}': ${(_d = metadata === null || metadata === void 0 ? void 0 : metadata.docsFragment) !== null && _d !== void 0 ? _d : ''}`.trim();
572
- }
573
- sections.push(summary);
537
+ sections.push("Impersonation supported: pass 'impersonationResourceId' for write attribution.");
574
538
  }
575
539
  const combined = sections.join(' ');
576
540
  const output = truncateDescription(combined);