Skip to content

Commit 881fae6

Browse files
committed
feat(tools): add incremental sync and draft postings to Ashby reads
list_jobs now accepts and returns Ashby's syncToken, so a scheduled sync costs O(changed reqs) instead of rescanning every req. Ashby only returns the token on the last page, which the param description states. list_job_postings gains includeUnpublishedJobPostings, plus the posting status field - without status a caller cannot tell a returned draft from a published posting, which makes the flag useless.
1 parent fbfb7f0 commit 881fae6

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

apps/sim/tools/ashby/list_job_postings.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ interface AshbyListJobPostingsParams {
66
location?: string
77
department?: string
88
listedOnly?: boolean
9+
includeUnpublishedJobPostings?: boolean
910
jobBoardId?: string
1011
}
1112

@@ -22,6 +23,7 @@ interface AshbyJobPostingSummary {
2223
} | null
2324
workplaceType: string | null
2425
employmentType: string | null
26+
status: string | null
2527
isListed: boolean
2628
publishedDate: string | null
2729
applicationDeadline: string | null
@@ -72,6 +74,13 @@ export const listJobPostingsTool: ToolConfig<
7274
visibility: 'user-or-llm',
7375
description: 'When true, only returns listed (publicly visible) job postings (default false)',
7476
},
77+
includeUnpublishedJobPostings: {
78+
type: 'boolean',
79+
required: false,
80+
visibility: 'user-or-llm',
81+
description:
82+
'When true, also returns unpublished (Draft) job postings. The endpoint already returns both listed and unlisted published postings by default, so this only adds drafts.',
83+
},
7584
jobBoardId: {
7685
type: 'string',
7786
required: false,
@@ -90,6 +99,9 @@ export const listJobPostingsTool: ToolConfig<
9099
if (params.location) body.location = params.location
91100
if (params.department) body.department = params.department
92101
if (params.listedOnly !== undefined) body.listedOnly = params.listedOnly
102+
if (params.includeUnpublishedJobPostings !== undefined) {
103+
body.includeUnpublishedJobPostings = params.includeUnpublishedJobPostings
104+
}
93105
if (params.jobBoardId) body.jobBoardId = params.jobBoardId.trim()
94106
return body
95107
},
@@ -127,6 +139,7 @@ export const listJobPostingsTool: ToolConfig<
127139
: null,
128140
workplaceType: (jp.workplaceType as string) ?? null,
129141
employmentType: (jp.employmentType as string) ?? null,
142+
status: (jp.status as string) ?? null,
130143
isListed: (jp.isListed as boolean) ?? false,
131144
publishedDate: (jp.publishedDate as string) ?? null,
132145
applicationDeadline: (jp.applicationDeadline as string) ?? null,
@@ -186,6 +199,11 @@ export const listJobPostingsTool: ToolConfig<
186199
description: 'Employment type (FullTime, PartTime, Intern, Contract, Temporary)',
187200
optional: true,
188201
},
202+
status: {
203+
type: 'string',
204+
description: 'Posting status (Draft or Published)',
205+
optional: true,
206+
},
189207
isListed: { type: 'boolean', description: 'Whether the posting is publicly listed' },
190208
publishedDate: {
191209
type: 'string',

apps/sim/tools/ashby/list_jobs.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,15 @@ export const listJobsTool: ToolConfig<AshbyListJobsParams, AshbyListJobsResponse
2626
type: 'number',
2727
required: false,
2828
visibility: 'user-or-llm',
29-
description: 'Number of results per page (default 100)',
29+
description:
30+
'Number of results per page (default and max 100). Ashby silently caps larger values rather than erroring.',
31+
},
32+
syncToken: {
33+
type: 'string',
34+
required: false,
35+
visibility: 'user-or-llm',
36+
description:
37+
'Opaque token from a prior sync to fetch only jobs changed since then. Ashby only returns a new syncToken on the last page, so drain moreDataAvailable/nextCursor before persisting it.',
3038
},
3139
status: {
3240
type: 'string',
@@ -75,6 +83,7 @@ export const listJobsTool: ToolConfig<AshbyListJobsParams, AshbyListJobsResponse
7583
const body: Record<string, unknown> = { expand: ['openings', 'location'] }
7684
if (params.cursor) body.cursor = params.cursor
7785
if (params.perPage) body.limit = params.perPage
86+
if (params.syncToken) body.syncToken = params.syncToken
7887
if (params.status) body.status = [params.status]
7988
const isoToMs = (iso: string): number | null => {
8089
const ms = new Date(iso).getTime()
@@ -117,6 +126,7 @@ export const listJobsTool: ToolConfig<AshbyListJobsParams, AshbyListJobsResponse
117126
jobs: (data.results ?? []).map(mapJob),
118127
moreDataAvailable: data.moreDataAvailable ?? false,
119128
nextCursor: data.nextCursor ?? null,
129+
syncToken: data.syncToken ?? null,
120130
},
121131
}
122132
},
@@ -139,5 +149,11 @@ export const listJobsTool: ToolConfig<AshbyListJobsParams, AshbyListJobsResponse
139149
description: 'Opaque cursor for fetching the next page',
140150
optional: true,
141151
},
152+
syncToken: {
153+
type: 'string',
154+
description:
155+
'Opaque sync token returned after the last page; pass on the next sync to fetch only changed jobs',
156+
optional: true,
157+
},
142158
},
143159
}

0 commit comments

Comments
 (0)