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.
- package/README.md +112 -202
- package/dist/nodes/Autotask/AutotaskAiTools.node.js +1 -1
- package/dist/nodes/Autotask/ai-tools/description-builders.d.ts.map +1 -1
- package/dist/nodes/Autotask/ai-tools/description-builders.js +15 -51
- package/dist/nodes/Autotask/ai-tools/description-builders.js.map +1 -1
- package/dist/nodes/Autotask/ai-tools/error-formatter.d.ts +1 -0
- package/dist/nodes/Autotask/ai-tools/error-formatter.d.ts.map +1 -1
- package/dist/nodes/Autotask/ai-tools/error-formatter.js +1 -0
- package/dist/nodes/Autotask/ai-tools/error-formatter.js.map +1 -1
- package/dist/nodes/Autotask/ai-tools/operation-handlers/ticket-convenience.d.ts.map +1 -1
- package/dist/nodes/Autotask/ai-tools/operation-handlers/ticket-convenience.js +24 -16
- package/dist/nodes/Autotask/ai-tools/operation-handlers/ticket-convenience.js.map +1 -1
- package/dist/nodes/Autotask/ai-tools/schema-generator.js +7 -7
- package/dist/nodes/Autotask/ai-tools/schema-generator.js.map +1 -1
- package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.d.ts +21 -0
- package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.d.ts.map +1 -1
- package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.js +37 -0
- package/dist/nodes/Autotask/ai-tools/tool-executor-helpers.js.map +1 -1
- package/dist/nodes/Autotask/ai-tools/tool-executor.d.ts.map +1 -1
- package/dist/nodes/Autotask/ai-tools/tool-executor.js +16 -1
- package/dist/nodes/Autotask/ai-tools/tool-executor.js.map +1 -1
- package/dist/package.json +11 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- 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
|
-
**
|
|
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
|
-
**
|
|
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
|
-
|
|
304
|
+
The agent calls a tool like this (the LLM emits the JSON; you don't write it manually):
|
|
319
305
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
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
|
-
|
|
319
|
+
**2. Inspect when needed**
|
|
335
320
|
|
|
336
|
-
|
|
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
|
-
|
|
342
|
-
- `
|
|
343
|
-
- `
|
|
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
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
339
|
+
#### Tool Configuration for Maximum Effectiveness
|
|
369
340
|
|
|
370
|
-
|
|
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
|
-
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
**
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
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
|
-
**
|
|
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
|
|
387
|
+
**Scenario: Create a contact at an existing company**
|
|
445
388
|
|
|
446
|
-
|
|
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
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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
|
-
//
|
|
509
|
-
// resolutions: [{ field: 'status', from: 'New', to: 1, method: 'picklist' }]
|
|
405
|
+
// → { records: [{ id: 12345, companyName: "Tech Solutions Ltd", ... }], summary: "..." }
|
|
510
406
|
|
|
511
|
-
//
|
|
512
|
-
|
|
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
|
-
|
|
515
|
-
|
|
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
|
-
//
|
|
519
|
-
|
|
520
|
-
|
|
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
|
|
432
|
+
Errors return a flat JSON shape with structured fields the agent can act on directly:
|
|
528
433
|
|
|
529
|
-
```
|
|
530
|
-
// Error response includes actionable guidance
|
|
434
|
+
```jsonc
|
|
531
435
|
{
|
|
532
|
-
"error":
|
|
533
|
-
"
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
- **
|
|
546
|
-
- **
|
|
547
|
-
- **Use
|
|
548
|
-
- **
|
|
549
|
-
- **
|
|
550
|
-
- **
|
|
551
|
-
- **
|
|
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
|
-
**
|
|
559
|
-
**
|
|
560
|
-
**
|
|
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 =
|
|
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":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQrD,eAAO,MAAM,iCAAiC,sBAAsB,CAAC;AAkCrE,wBAAgB,sBAAsB,IAAI,MAAM,
|
|
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
|
|
76
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
527
|
+
sections.push("Company identifier priority: domain from email/website first; fall back to companyName contains only when no domain signal.");
|
|
537
528
|
}
|
|
538
|
-
|
|
539
|
-
sections.push(`
|
|
540
|
-
sections.push(
|
|
541
|
-
|
|
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(
|
|
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);
|