feat: add work items toolset via GraphQL API#362
feat: add work items toolset via GraphQL API#362DarkByteZero wants to merge 12 commits intozereight:mainfrom
Conversation
New `workitems` toolset with 6 tools replacing REST-based issue operations: - get_work_item: fetch single item with all widgets (status, hierarchy, labels, health status, dates, milestone, linked items, time tracking, development/MRs, custom fields) — output optimized, omits null/empty values - list_work_items: list/filter with pagination, returns lean summary per item - create_work_item: create any type with labels, assignees, weight, parent, health status, dates, milestone, confidential - update_work_item: consolidated update for all fields including status (by ID), parent/children hierarchy, linked items (related/blocks/blocked_by), custom fields, health status, dates, milestone - convert_work_item_type: type conversion via workItemConvert mutation - list_work_item_statuses: discover available statuses per type Supports all 9 work item types: issue, task, incident, test_case, epic, key_result, objective, requirement, ticket. Also fixes: - createIssue now passes all fields via spread (issue_type, weight were dropped) - Adds reusable GraphQL infrastructure (executeGraphQL, resolveWorkItemGID, resolveWorkItemTypeGID, resolveProjectPath)
|
Later issues tools could be fully replaced by new WorkItem API actually. |
- Add list_custom_field_definitions tool to discover available custom fields per work item type - Enhance getWorkItem with iteration, progress, color, linked items details, weight rollup, confidential, author, createdAt/closedAt - Enhance list_work_item_statuses to return supported conversion types and allowed child/parent types - Add iteration_id support to create_work_item and update_work_item - Expand all type enums to include all 9 work item types - Remove tier annotations from descriptions
- Add move_work_item tool using GraphQL issueMove mutation - Remove redundant "Uses GitLab GraphQL API" from tool descriptions
…ools - list_work_item_notes: threaded discussions with pagination and sort - create_work_item_note: supports markdown, internal notes, and threaded replies
- Replace separate REST-based resolveLabelIds and resolveUserIds with single resolveNamesToIds GraphQL call (labels + users in one request) - Fix assignees: use assigneeIds (UserID GIDs) instead of assigneeUsernames which isn't supported by WorkItemWidgetAssigneesInput - Fix description type in update: String -> String! (non-null required) - Fix linkType: String! -> WorkItemRelatedLinkType! for linked items - Remove misleading 'labels' field from UpdateWorkItemSchema (only add_labels/remove_labels remain)
…inked items Add namespace.fullPath to children and linkedItems GraphQL queries so work items from other projects include their project path in the response.
There was a problem hiding this comment.
Pull request overview
This PR adds a new opt-in workitems toolset that exposes 10 GraphQL-based tools for managing GitLab work items (issues, tasks, epics, incidents, etc.). It also fixes the createIssue REST function which was silently dropping issue_type and weight fields.
Changes:
- Added 10 new work item tools (get, list, create, update, convert, move, statuses, custom fields, notes) backed by GitLab GraphQL API, with reusable GraphQL infrastructure (
executeGraphQL,resolveWorkItemGID, etc.) - Fixed
createIssueto pass all schema fields (includingissue_typeandweight) to the API instead of only a hardcoded subset - Added corresponding Zod schemas for all new work item tools in
schemas.ts
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| schemas.ts | Added work item Zod schemas; fixed CreateIssueOptionsSchema/CreateIssueSchema/UpdateIssueSchema to properly include issue_type and weight |
| index.ts | Added 10 work item tool definitions, toolset registration, GraphQL helper functions, and all work item CRUD/query implementations; fixed createIssue body construction |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix toUpperCase() for multi-word types (e.g. "Test Case" → "TEST_CASE") - Add pagination limit to labels query (first: 250) - List all 9 supported types in create_work_item description
…tatus, and fix custom fields - Add get_timeline_events and create_timeline_event tools for incident management - Fold severity and escalation_status into update_work_item (incident only) - Fix list_custom_field_definitions to return selectOptions and workItemTypes - Remove redundant resolveProjectPath call in updateWorkItem
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async function resolveProjectPath(projectId: string): Promise<string> { | ||
| projectId = decodeURIComponent(projectId); | ||
| const effectiveProjectId = getEffectiveProjectId(projectId); | ||
| const projectUrl = new URL( | ||
| `${getEffectiveApiUrl()}/projects/${encodeURIComponent(effectiveProjectId)}` | ||
| ); | ||
| const projectResponse = await fetch(projectUrl.toString(), { | ||
| ...getFetchConfig(), | ||
| }); | ||
| await handleGitLabError(projectResponse); | ||
| const project: any = await projectResponse.json(); | ||
| return project.path_with_namespace; | ||
| } |
| // --- Incident timeline event tools --- | ||
| { | ||
| name: "get_timeline_events", | ||
| description: | ||
| "List timeline events for an incident. Returns chronological events with notes, timestamps, and tags (Start time, End time, Impact detected, etc.).", | ||
| inputSchema: toJSONSchema(GetTimelineEventsSchema), | ||
| }, | ||
| { | ||
| name: "create_timeline_event", | ||
| description: | ||
| "Create a timeline event on an incident. Supports tags: 'Start time', 'End time', 'Impact detected', 'Response initiated', 'Impact mitigated', 'Cause identified'.", | ||
| inputSchema: toJSONSchema(CreateTimelineEventSchema), | ||
| }, |
index.ts
Outdated
| const { workItemGID: incidentGID } = await resolveWorkItemGID(projectId, incidentIid); | ||
|
|
||
| const data = await executeGraphQL<{ project: any }>( | ||
| `query($fullPath: ID!, $incidentId: IssueID!) { | ||
| project(fullPath: $fullPath) { | ||
| incidentManagementTimelineEvents(incidentId: $incidentId) { | ||
| nodes { | ||
| id | ||
| note | ||
| noteHtml | ||
| action | ||
| occurredAt | ||
| createdAt | ||
| timelineEventTags { | ||
| nodes { | ||
| id | ||
| name | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }`, | ||
| { fullPath: projectPath, incidentId: incidentGID } |
index.ts
Outdated
| const { workItemGID: incidentGID } = await resolveWorkItemGID(projectId, incidentIid); | ||
|
|
||
| const variables: Record<string, any> = { | ||
| input: { | ||
| incidentId: incidentGID, |
index.ts
Outdated
| const projectPath = await resolveProjectPath(projectId); | ||
| const { workItemGID: incidentGID } = await resolveWorkItemGID(projectId, incidentIid); |
index.ts
Outdated
| // Map input names to GitLab work item type names | ||
| const typeNameMap: Record<string, string> = { | ||
| issue: "Issue", | ||
| task: "Task", | ||
| incident: "Incident", | ||
| test_case: "Test Case", | ||
| epic: "Epic", | ||
| key_result: "Key Result", | ||
| objective: "Objective", | ||
| requirement: "Requirement", | ||
| ticket: "Ticket", | ||
| }; | ||
|
|
||
| const targetName = typeNameMap[typeName]; |
- Fix GID type mismatch: timeline events use Issue GID, not WorkItem GID - Remove redundant resolveProjectPath call in getTimelineEvents - Deduplicate typeNameMap by reusing WORK_ITEM_TYPE_NAMES constant
… enums - Use z.coerce.number() for all iid, weight, and numeric fields - Accept type values in any case (e.g. "ISSUE", "Issue", "issue") - Deduplicate typeNameMap by reusing WORK_ITEM_TYPE_NAMES - Fix GID type for timeline events (Issue vs WorkItem) - Remove redundant resolveProjectPath in getTimelineEvents
Summary
GitLab standardizes planning objects around Work Items. The legacy Issues REST API remains supported, but it does not cover all modern work item capabilities. In particular, richer work item features such as configurable statuses and custom fields are exposed through the Work Item APIs, making GraphQL the more complete integration surface today.
This PR adds a new
workitemstoolset (opt-in viaGITLAB_TOOLSETS) with 10 tools that cover the full work item lifecycle using the GraphQL API:All 9 GitLab work item types are supported: issue, task, incident, test_case, epic, key_result, objective, requirement, ticket.
Additional changes
createIssuewhereissue_typeandweightfields were silently droppedexecuteGraphQL,resolveWorkItemGID,resolveWorkItemTypeGID,resolveProjectPathisDefault: false) so it does not affect existing usersTest plan