iit-mcp-autotask 0.13.1 → 0.14.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 +7 -1
- package/dist/tools/context/types.d.ts +2 -1
- package/dist/tools/dispatch.d.ts +1 -1
- package/dist/tools/dispatch.js +4 -2
- package/dist/tools/meta.js +34 -3
- package/dist/tools/schemas.d.ts +17 -4
- package/dist/tools/schemas.js +23 -3
- package/dist/tools/server-version.d.ts +1 -1
- package/dist/tools/server-version.js +1 -1
- package/dist/tools/server.d.ts +1 -1
- package/package.json +1 -1
- package/server.json +1 -1
- package/skills/filter-semantics.md +4 -2
package/README.md
CHANGED
|
@@ -44,7 +44,13 @@ its contract, `autotask_read` runs it.
|
|
|
44
44
|
- `autotask_read` runs any read by exact key, or up to 10 at once (`items`). Unbilled work
|
|
45
45
|
(`companies.unbilledWork`), contract profitability (`contracts.profitability`), aggregates
|
|
46
46
|
(`operations.aggregate`) and SLA health (`tickets.slaHealthCheck`) run here; `autotask_guide`
|
|
47
|
-
holds their recipes.
|
|
47
|
+
holds their recipes. The two time-entry window keys (`time_entries.dateWorkedWindow`,
|
|
48
|
+
`time_entries.postedWithin`) also take flat named inputs instead of `args`, for clients that cannot
|
|
49
|
+
send a mixed-type array (Copilot Studio): `{operation, from, to, posted?, limit?, ticketID?,
|
|
50
|
+
resourceID?}`, `from`/`to` as inclusive `YYYY-MM-DD` dateWorked days (never UTC-converted),
|
|
51
|
+
`ticketID`/`resourceID` as numbers, no `tz` (it does not shift dateWorked). The SDK's
|
|
52
|
+
`foldFlattenedOpts` maps them onto its named invoke form, so the result and `truncated` flag are
|
|
53
|
+
the positional call's. `autotask_read` and `autotask_fetch_many` answer ONE envelope (the next minor,
|
|
48
54
|
breaking): `data = { results: Slot[], ok, failed, budget?, budgetWarning? }`, an array in input
|
|
49
55
|
order even for a single read (`data.results[0].result`). A slot is `{ ok: true, operation, result,
|
|
50
56
|
windowNote? }` or `{ ok: false, operation, error }`; fetch_many slots also echo `resource` and `id`
|
|
@@ -33,7 +33,8 @@ export interface QueryWalkResult {
|
|
|
33
33
|
/** The SDK operations the handler layer drives, bound in ONE place (the mock seam). */
|
|
34
34
|
export interface ToolOps {
|
|
35
35
|
/** The MCP request's AbortSignal, when the transport provides one: an abandoned request stops consuming vendor budget. */
|
|
36
|
-
|
|
36
|
+
/** `args` is positional, or (#173, the window keys) the SDK's named form keyed by the record's inputSchema names. */
|
|
37
|
+
invokeRead(client: ToolClient, operation: string, args?: readonly unknown[] | Record<string, unknown>, opts?: InvokeOptions, signal?: AbortSignal): Promise<unknown>;
|
|
37
38
|
invokeWrite(client: ToolClient, operation: string, args?: readonly unknown[], opts?: InvokeOptions, signal?: AbortSignal): Promise<unknown>;
|
|
38
39
|
invokeDelete(client: ToolClient, operation: string, args?: readonly unknown[], opts?: InvokeOptions, signal?: AbortSignal): Promise<unknown>;
|
|
39
40
|
resolveAny(client: ToolClient, identifier: number | string, opts?: {
|
package/dist/tools/dispatch.d.ts
CHANGED
|
@@ -78,4 +78,4 @@ export interface ReadOutcome {
|
|
|
78
78
|
* governed invoke (the SDK's single read governor) and the untrusted projection of the result.
|
|
79
79
|
* Errors are THROWN — the frame wraps them once, the `items` form maps them per slot.
|
|
80
80
|
*/
|
|
81
|
-
export declare function readOneItem(ctx: ToolContext, operation: string, args: unknown[], signal: AbortSignal | undefined): Promise<ReadOutcome>;
|
|
81
|
+
export declare function readOneItem(ctx: ToolContext, operation: string, args: unknown[] | Record<string, unknown>, signal: AbortSignal | undefined): Promise<ReadOutcome>;
|
package/dist/tools/dispatch.js
CHANGED
|
@@ -191,7 +191,9 @@ export async function readOneItem(ctx, operation, args, signal) {
|
|
|
191
191
|
}
|
|
192
192
|
assertOperationPermitted(operation, rec, ctx.config, ctx.log);
|
|
193
193
|
// Issue #1: strip ONE exact outer <untrusted_content> wrapper from the string inputs.
|
|
194
|
-
const
|
|
194
|
+
const stripped = stripUntrustedDeep(args);
|
|
195
|
+
// A named-form object (#173) only arrives for the window keys, which no positional branch below touches.
|
|
196
|
+
const cleanArgs = Array.isArray(stripped) ? stripped : [];
|
|
195
197
|
// #18: the *.query / *.count ops take a params bag whose `filter` top-level shape is refused
|
|
196
198
|
// pre-request (zero wire on a refused shape).
|
|
197
199
|
if (operation.endsWith('.query') || operation.endsWith('.count')) {
|
|
@@ -249,7 +251,7 @@ export async function readOneItem(ctx, operation, args, signal) {
|
|
|
249
251
|
cleanArgs[0] = { ...bag, labels: true };
|
|
250
252
|
}
|
|
251
253
|
}
|
|
252
|
-
const result = await ctx.ops.invokeRead(ctx.client, operation, cleanArgs, undefined, signal);
|
|
254
|
+
const result = await ctx.ops.invokeRead(ctx.client, operation, Array.isArray(stripped) ? cleanArgs : stripped, undefined, signal);
|
|
253
255
|
if (result === undefined)
|
|
254
256
|
return { aborted: true, result: undefined };
|
|
255
257
|
const post = READ_POSTPROCESS[operation];
|
package/dist/tools/meta.js
CHANGED
|
@@ -16,15 +16,16 @@
|
|
|
16
16
|
* fail-closed refusal, then the work, with the SDK error contract mapped on failure.
|
|
17
17
|
*/
|
|
18
18
|
import { AutotaskConfigError } from 'node-autotask';
|
|
19
|
+
import { foldFlattenedOpts } from 'node-autotask/operations';
|
|
19
20
|
import { CATALOG, SDK_VERSION, TOOL_NAME_BY_OP, opsForTool, recordById, servedToolName, untrustedFieldsOf } from './catalog-data.js';
|
|
20
21
|
import { releaseClientOnError } from './context.js';
|
|
21
|
-
import { abortedAnswer, InputInvalidError, readOneItem, requestSecrets } from './dispatch.js';
|
|
22
|
+
import { abortedAnswer, InputInvalidError, NeedsInputError, readOneItem, requestSecrets } from './dispatch.js';
|
|
22
23
|
import { zoneClock } from './clock.js';
|
|
23
24
|
import { crossResourceUntrusted, honestReadError, markResult, ok, typedErrorPayload } from './results.js';
|
|
24
25
|
import { bm25Rank } from './rank.js';
|
|
25
26
|
import { playbooksFor } from './guide.js';
|
|
26
27
|
import { SERVER_NAME, SERVER_VERSION } from './server-version.js';
|
|
27
|
-
import { CATALOG_INPUT, DESCRIBE_INPUT, COMPANY_FULL_PROFILE_INPUT, CONFIGURATION_ITEM_PROFILE_INPUT, CONTACT_FULL_PROFILE_INPUT, CONTRACT_FULL_PROFILE_INPUT, FETCH_MANY_INPUT, INVOICE_GET_INPUT, PROJECT_GET_CONTEXT_INPUT, QUERY_INPUT, QUOTE_GET_INPUT, RESOLVE_INPUT, RESOURCE_WORKLOAD_INPUT, SERVICE_CALL_FULL_PROFILE_INPUT, TICKET_FULL_CONTEXT_INPUT, QUERY_LIMIT, READ_INPUT, TENANT_STATUS_INPUT, TENANT_STATUS_PARTS, closedInput, } from './schemas.js';
|
|
28
|
+
import { CATALOG_INPUT, DESCRIBE_INPUT, COMPANY_FULL_PROFILE_INPUT, CONFIGURATION_ITEM_PROFILE_INPUT, CONTACT_FULL_PROFILE_INPUT, CONTRACT_FULL_PROFILE_INPUT, FETCH_MANY_INPUT, INVOICE_GET_INPUT, PROJECT_GET_CONTEXT_INPUT, QUERY_INPUT, QUOTE_GET_INPUT, RESOLVE_INPUT, RESOURCE_WORKLOAD_INPUT, SERVICE_CALL_FULL_PROFILE_INPUT, TICKET_FULL_CONTEXT_INPUT, QUERY_LIMIT, READ_INPUT, TENANT_STATUS_INPUT, TENANT_STATUS_PARTS, WINDOW_KEYS, WINDOW_OPS, closedInput, } from './schemas.js';
|
|
28
29
|
import { refusalReason } from '../policy.js';
|
|
29
30
|
/** Search text per catalog row (key words + purpose), built once. */
|
|
30
31
|
const ROW_TEXT = CATALOG.catalog.map((r) => `${r.operation} ${r.operation.replace(/[._]/g, ' ')} ${r.purpose ?? ''}`);
|
|
@@ -250,6 +251,13 @@ async function guidanceFor(ctx, rec, reachable) {
|
|
|
250
251
|
example: `autotask_read {operation:"${rec.id}", args:[{filter:[{field:"id",op:"gt",value:0}],limit:10}]}`,
|
|
251
252
|
};
|
|
252
253
|
}
|
|
254
|
+
if (WINDOW_OPS.includes(rec.id)) {
|
|
255
|
+
// #173: the flat named form, for clients that cannot send the mixed positional [from, to, opts]
|
|
256
|
+
return {
|
|
257
|
+
namedInputs: 'from, to (YYYY-MM-DD dateWorked days, inclusive; never UTC-converted), posted, limit, ticketID, resourceID (numbers) as top-level autotask_read fields instead of args; same result and truncated flag. tz is not offered: it does not shift dateWorked.',
|
|
258
|
+
example: `autotask_read {operation:"${rec.id}", from:"2026-10-20", to:"2026-10-22", resourceID:123}`,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
253
261
|
if (op === 'moveToTicket') {
|
|
254
262
|
// the move ops (#107): zero wire, a pointer to the governed path
|
|
255
263
|
return {
|
|
@@ -307,6 +315,28 @@ async function describeRecord(ctx, operation, viaTool) {
|
|
|
307
315
|
...(names !== undefined ? { paramNames: names } : {}),
|
|
308
316
|
});
|
|
309
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* #173: the window keys' flat named inputs, folded by the SDK (`foldFlattenedOpts`) into its named
|
|
320
|
+
* invoke form `{ from, to, opts }`; undefined when none is given (the positional call, unchanged).
|
|
321
|
+
* Refused before any request: a named input on any other key or in the items form, together with
|
|
322
|
+
* positional args, or without from and to.
|
|
323
|
+
*/
|
|
324
|
+
function windowNamedArgs(ctx, args) {
|
|
325
|
+
const named = Object.fromEntries(WINDOW_KEYS.filter((k) => args[k] !== undefined).map((k) => [k, args[k]]));
|
|
326
|
+
const first = Object.keys(named)[0];
|
|
327
|
+
if (first === undefined)
|
|
328
|
+
return undefined;
|
|
329
|
+
const op = args.operation;
|
|
330
|
+
if (op === undefined || !WINDOW_OPS.includes(op)) {
|
|
331
|
+
throw new InputInvalidError(`read: ${first} is a named input of ${WINDOW_OPS.join(' and ')} only (with operation); other reads take args`, first);
|
|
332
|
+
}
|
|
333
|
+
if (args.args.length > 0)
|
|
334
|
+
throw new InputInvalidError(`read: ${op} takes named inputs or args, not both`, 'args');
|
|
335
|
+
const missing = ['from', 'to'].filter((k) => named[k] === undefined);
|
|
336
|
+
if (missing.length > 0)
|
|
337
|
+
throw new NeedsInputError(`read: ${op} needs both from and to (YYYY-MM-DD) with its named inputs`, missing[0], missing.map((k) => `/${k}`));
|
|
338
|
+
return foldFlattenedOpts(ctx.record(op), named);
|
|
339
|
+
}
|
|
310
340
|
/** `autotask_read`: one read by exact key, or up to 10 (`items`) with per-item results. */
|
|
311
341
|
export function buildRead(ctx) {
|
|
312
342
|
return {
|
|
@@ -317,8 +347,9 @@ export function buildRead(ctx) {
|
|
|
317
347
|
if ((args.operation === undefined) === (args.items === undefined)) {
|
|
318
348
|
throw new InputInvalidError('read: pass exactly one of operation (with args) or items', 'operation');
|
|
319
349
|
}
|
|
350
|
+
const named = windowNamedArgs(ctx, args); // before the branch: a named input beside items is refused, never ignored
|
|
320
351
|
if (args.operation !== undefined) {
|
|
321
|
-
const out = await readOneItem(ctx, args.operation, args.args, signal);
|
|
352
|
+
const out = await readOneItem(ctx, args.operation, named ?? args.args, signal);
|
|
322
353
|
if (out.aborted)
|
|
323
354
|
return abortedAnswer(ctx.correlationId);
|
|
324
355
|
// The server-side note (issue #56: the profitability window default applied) rides the
|
package/dist/tools/schemas.d.ts
CHANGED
|
@@ -210,13 +210,26 @@ export declare const DESCRIBE_INPUT: z.ZodObject<{
|
|
|
210
210
|
resource: z.ZodOptional<z.ZodString>;
|
|
211
211
|
}, z.core.$strip>;
|
|
212
212
|
export declare const READ_MAX_ITEMS = 10;
|
|
213
|
+
/**
|
|
214
|
+
* #173: the two time-entry window keys also take flat, typed named inputs (the SDK's own names,
|
|
215
|
+
* as its MCP projection serves them), because a client that cannot send a mixed-type array cannot
|
|
216
|
+
* send their positional `[from, to, opts]`. `tz` is left out: it does not shift a dateWorked day.
|
|
217
|
+
*/
|
|
218
|
+
export declare const WINDOW_OPS: readonly string[];
|
|
219
|
+
export declare const WINDOW_KEYS: readonly ["from", "to", "posted", "limit", "ticketID", "resourceID"];
|
|
213
220
|
export declare const READ_INPUT: z.ZodObject<{
|
|
214
|
-
operation: z.ZodOptional<z.ZodString>;
|
|
215
|
-
args: z.ZodDefault<z.ZodArray<z.ZodUnknown
|
|
216
|
-
items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
221
|
+
operation: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
|
|
222
|
+
args: z.ZodPreprocess<z.ZodDefault<z.ZodArray<z.ZodUnknown>>, unknown>;
|
|
223
|
+
items: z.ZodPreprocess<z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
217
224
|
operation: z.ZodString;
|
|
218
225
|
args: z.ZodDefault<z.ZodArray<z.ZodUnknown>>;
|
|
219
|
-
}, z.core.$strict
|
|
226
|
+
}, z.core.$strict>>>, unknown>;
|
|
227
|
+
from: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
|
|
228
|
+
to: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
|
|
229
|
+
posted: z.ZodPreprocess<z.ZodOptional<z.ZodBoolean>, unknown>;
|
|
230
|
+
limit: z.ZodPreprocess<z.ZodOptional<z.ZodNumber>, unknown>;
|
|
231
|
+
ticketID: z.ZodPreprocess<z.ZodOptional<z.ZodNumber>, unknown>;
|
|
232
|
+
resourceID: z.ZodPreprocess<z.ZodOptional<z.ZodNumber>, unknown>;
|
|
220
233
|
}, z.core.$strip>;
|
|
221
234
|
export declare const RESOLVE_INPUT: z.ZodObject<{
|
|
222
235
|
identifier: z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>;
|
package/dist/tools/schemas.js
CHANGED
|
@@ -203,10 +203,30 @@ export const DESCRIBE_INPUT = z.object({
|
|
|
203
203
|
});
|
|
204
204
|
const READ_ITEM = z.strictObject({ operation: OP_KEY.describe('Exact read key.'), args: ARGS });
|
|
205
205
|
export const READ_MAX_ITEMS = 10;
|
|
206
|
+
/**
|
|
207
|
+
* #173: the two time-entry window keys also take flat, typed named inputs (the SDK's own names,
|
|
208
|
+
* as its MCP projection serves them), because a client that cannot send a mixed-type array cannot
|
|
209
|
+
* send their positional `[from, to, opts]`. `tz` is left out: it does not shift a dateWorked day.
|
|
210
|
+
*/
|
|
211
|
+
export const WINDOW_OPS = ['time_entries.dateWorkedWindow', 'time_entries.postedWithin'];
|
|
212
|
+
export const WINDOW_KEYS = ['from', 'to', 'posted', 'limit', 'ticketID', 'resourceID'];
|
|
213
|
+
/**
|
|
214
|
+
* An autotask_read input sent as null or '' is absent: form-filling clients (Copilot Studio) can
|
|
215
|
+
* send every unset optional that way, e.g. args: null beside the named window inputs. The advertised schema stays the plain scalar (no null union).
|
|
216
|
+
*/
|
|
217
|
+
const unset = (schema) => z.preprocess((v) => (v === null || v === '' ? undefined : v), schema);
|
|
206
218
|
export const READ_INPUT = z.object({
|
|
207
|
-
operation: OP_KEY.optional().describe('Exact read key, e.g. tickets.get (autotask_catalog finds it).'),
|
|
208
|
-
args: ARGS,
|
|
209
|
-
items: z.array(READ_ITEM).min(1).max(READ_MAX_ITEMS).optional().describe('Up to 10 reads in one call, each { operation, args }; use instead of operation.'),
|
|
219
|
+
operation: unset(OP_KEY.optional()).describe('Exact read key, e.g. tickets.get (autotask_catalog finds it).'),
|
|
220
|
+
args: unset(ARGS),
|
|
221
|
+
items: unset(z.array(READ_ITEM).min(1).max(READ_MAX_ITEMS).optional()).describe('Up to 10 reads in one call, each { operation, args }; use instead of operation.'),
|
|
222
|
+
// One description for the set: every served byte counts against the readonly-core budget. The SDK
|
|
223
|
+
// refuses a from/to that is not a real YYYY-MM-DD day, naming it, before any request.
|
|
224
|
+
from: unset(z.string().optional()).describe('time_entries.dateWorkedWindow/postedWithin only, instead of args: from, to are YYYY-MM-DD dateWorked days (inclusive); also posted, limit, ticketID, resourceID.'),
|
|
225
|
+
to: unset(z.string().optional()),
|
|
226
|
+
posted: unset(z.boolean().optional()),
|
|
227
|
+
limit: unset(z.number().int().min(1).optional()),
|
|
228
|
+
ticketID: unset(z.number().int().nonnegative().optional()),
|
|
229
|
+
resourceID: unset(z.number().int().nonnegative().optional()),
|
|
210
230
|
});
|
|
211
231
|
export const RESOLVE_INPUT = z.object({
|
|
212
232
|
identifier: z.union([z.number().int().nonnegative(), z.string().min(1).max(200)]).describe('Numeric id, name, ticket number, serial or email. resources: numeric identifiers are looked up as Resource ids.'),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** The wire identity of this server: a leaf module (no imports) so any tool can read it without an import cycle. */
|
|
2
2
|
export const SERVER_NAME = 'iit-mcp-autotask';
|
|
3
|
-
export const SERVER_VERSION = '0.
|
|
3
|
+
export const SERVER_VERSION = '0.14.0';
|
|
4
4
|
//# sourceMappingURL=server-version.js.map
|
package/dist/tools/server.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export declare function serverInstructions(config: Pick<Config, 'AUTOTASK_PROFIL
|
|
|
60
60
|
/** The full identity stamp (the `/metadata` build block — the era pair, FR-2). */
|
|
61
61
|
export declare const SERVER_IDENTITY: {
|
|
62
62
|
readonly name: "iit-mcp-autotask";
|
|
63
|
-
readonly version: "0.
|
|
63
|
+
readonly version: "0.14.0";
|
|
64
64
|
readonly mcpProtocolBaseline: "2026-07-28";
|
|
65
65
|
readonly legacyProtocolFallback: "2025-11-25";
|
|
66
66
|
};
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -5,7 +5,7 @@ version: 1
|
|
|
5
5
|
profile: readonly
|
|
6
6
|
description: Filter footguns for autotask_query: strict date lt, case-insensitive contains, FK 0 vs NULL, field-name checks, all-strings values.
|
|
7
7
|
when_not_to_use: the filter grammar itself (the 13 operators + and/or grouping, server instructions); the per-operation notes (autotask_describe)
|
|
8
|
-
ops: ["autotask_query:tickets.query", "autotask_query:time_entries.query", "autotask_query:service_calls.query", "autotask_query:contracts.query", "autotask_query:time_off_requests.query", "autotask_read:operations.fieldCatalog"]
|
|
8
|
+
ops: ["autotask_query:tickets.query", "autotask_query:time_entries.query", "autotask_query:service_calls.query", "autotask_query:contracts.query", "autotask_query:time_off_requests.query", "autotask_read:operations.fieldCatalog", "autotask_read:time_entries.dateWorkedWindow", "autotask_read:time_entries.postedWithin"]
|
|
9
9
|
inputs: {"type": "object", "required": [], "properties": {}}
|
|
10
10
|
outcomes: ["ok", "error"]
|
|
11
11
|
hazards: ["gt/lt around a day boundary silently drops an edge day", "ticketID eq 0 finds nothing (time_entries store NULL)", "an unknown field name is a zero-query-wire CONFIG_ERROR (0.20.0 pre-validation; a cold field cache makes one vendor metadata GET first)"]
|
|
@@ -28,7 +28,7 @@ No inputs: this is a reference page about the filter behaviour of autotask_query
|
|
|
28
28
|
3. tickets.search is a vendor contains on the TITLE only: no free-text search, no matched-field reporting, and vendor contains is looser than a literal substring (case/token matching can return MORE hits than a local title-substring check). The per-field contains of tickets.query is the precise tool.
|
|
29
29
|
4. Unassigned FKs are not uniform. tickets store 0; time_entries store NULL. Unallocated time needs notExist (ticketID eq 0 finds nothing); assignedResourceID eq 0 and notExist differ.
|
|
30
30
|
5. Field names are vendor casing, and an unknown field name now fails pre-dispatch as a typed CONFIG_ERROR with the field-catalog pointer, with zero query wire (0.20.0 pre-validation), on all five autotask_query operations (tickets.query, time_entries.query, service_calls.query, contracts.query, time_off_requests.query). One udf: true condition per query is exempt from the name check. List names for the queried resource with the scoped call `autotask_read {operation:"operations.fieldCatalog", args:[{resources:["<resource>"]}]}` (add `fields: [names]` to project; a scoped call also returns picklist labels by default on this server). Never the bare `operations.fieldCatalog`: it serves the whole five-resource catalog (~85 KB) and has no row for time_entries, service_calls, contracts or time_off_requests. Do not guess names. The answer is `data.results[0].result`.
|
|
31
|
-
6. Some clients (Copilot Studio) fail locally, before any request, when an array mixes value types: a number and a string in one filter, or dateWorkedWindow args (strings plus an object). For such a client, write every filter value as a string ("<resource id>", "2026-10-22", "true")
|
|
31
|
+
6. Some clients (Copilot Studio) fail locally, before any request, when an array mixes value types: a number and a string in one filter, or dateWorkedWindow args (strings plus an object). For such a client, write every filter value as a string ("<resource id>", "2026-10-22", "true"). For a time entry window use the named form instead of args, all flat scalars: `autotask_read {operation:"time_entries.dateWorkedWindow", from:"2026-10-20", to:"2026-10-22", resourceID:<resource id>}` (also posted, limit, ticketID; resourceID and ticketID are numbers; the same for time_entries.postedWithin). It returns the same rows, counts and truncated flag as the positional call; from and to are inclusive YYYY-MM-DD dateWorked days, never UTC-converted, and there is no tz input (tz does not shift dateWorked). The server and SDK pass filter values through unchanged; string dates and ids are confirmed to work, other types are not verified on every field.
|
|
32
32
|
|
|
33
33
|
## Guardrails
|
|
34
34
|
|
|
@@ -68,4 +68,6 @@ No inputs: this is a reference page about the filter behaviour of autotask_query
|
|
|
68
68
|
| autotask_query | contracts.query | read | - |
|
|
69
69
|
| autotask_query | time_off_requests.query | read | - |
|
|
70
70
|
| autotask_read | operations.fieldCatalog | read | - |
|
|
71
|
+
| autotask_read | time_entries.dateWorkedWindow | read | from, to |
|
|
72
|
+
| autotask_read | time_entries.postedWithin | read | from, to |
|
|
71
73
|
<!-- generated:end -->
|