Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 21x 21x 21x 21x 21x 21x 21x 21x 21x 21x 182x 21x 62x 21x 30x 30x 21x 27x 27x 23x 23x 22x 23x 22x 4x 14x 14x 14x 13x 12x 12x 11x 1x 21x 21x | import { gql } from 'graphql-tag';
import type { DocumentNode } from 'graphql';
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
import { ConnectionManager } from '../../services/ConnectionManager';
import { getGitLabBaseUrl } from '../../utils/gitlab-base-url';
import { graphqlSupports } from '../instance-version';
import { extractSimpleId } from '../../utils/idConversion';
export const DUO_RESPONSE_BYTES = 4 * 1024 * 1024;
export interface PageInfo {
hasNextPage: boolean;
endCursor: string | null;
}
export interface Workflow {
id: string;
projectId: string | null;
humanStatus: string;
statusName?: string | null;
status?: string | null;
webUrl?: string | null;
createdAt: string;
workflowDefinition?: string | null;
project?: { id: string; fullPath: string } | null;
summary?: string | null;
userPermissions?: { resumeDuoWorkflow?: boolean } | null;
}
export interface WorkflowPage {
nodes: Workflow[];
pageInfo: PageInfo;
}
const METADATA = `
id projectId humanStatus createdAt
statusName @optional
status @optional
webUrl @optional
workflowDefinition @optional
project @optional { id fullPath }
`;
const LIST = gql`
query DuoSessionMetadata($first: Int!, $after: String) {
duoWorkflowWorkflows(first: $first, after: $after) {
nodes { ${METADATA} }
pageInfo { hasNextPage endCursor }
}
}
`;
const GET = gql`
query DuoSessionMetadataById($id: AiDuoWorkflowsWorkflowID!) {
duoWorkflowWorkflows(workflowId: $id, first: 1) {
nodes { ${METADATA} }
pageInfo { hasNextPage endCursor }
}
}
`;
export function requestDuo<T>(
document: TypedDocumentNode<T, Record<string, unknown>>,
variables: Record<string, unknown> = {},
): Promise<T> {
return ConnectionManager.getInstance()
.getClient(getGitLabBaseUrl())
.request(document, variables, undefined, DUO_RESPONSE_BYTES);
}
export const workflowGid = (id: string): string =>
`gid://gitlab/Ai::DuoWorkflows::Workflow/${extractSimpleId(id)}`;
export async function workflowPage(first: number, after?: string): Promise<WorkflowPage> {
const result = await requestDuo<{ duoWorkflowWorkflows: WorkflowPage }>(LIST, { first, after });
return result.duoWorkflowWorkflows;
}
/** Older GraphQL connections have no workflowId argument; scan metadata with a fixed ceiling. */
export async function readWorkflow(id: string): Promise<Workflow> {
const simple = extractSimpleId(id);
if (graphqlSupports('Query', 'duoWorkflowWorkflows', 'workflowId')) {
const result = await requestDuo<{ duoWorkflowWorkflows: WorkflowPage }>(GET, {
id: workflowGid(id),
});
const workflow = result.duoWorkflowWorkflows.nodes.find(
(row) => extractSimpleId(row.id) === simple,
);
if (!workflow) throw new Error('Duo session is unavailable to this account');
return workflow;
}
let after: string | undefined;
for (let page = 0; page < 10; page++) {
const result = await workflowPage(100, after);
const workflow = result.nodes.find((row) => extractSimpleId(row.id) === simple);
if (workflow) return workflow;
if (!result.pageInfo.hasNextPage) throw new Error('Duo session is unavailable to this account');
const next = result.pageInfo.endCursor;
if (!next || next === after) throw new Error('GitLab did not advance Duo session pagination');
after = next;
}
throw new Error('Duo session lookup reached its metadata limit; inspect the session in GitLab');
}
export interface Message {
content: string | null;
role: string | null;
messageType: string | null;
}
export const DETAILS: DocumentNode = gql`
query DuoSessionDetails($id: AiDuoWorkflowsWorkflowID!) {
duoWorkflowWorkflows(workflowId: $id, first: 1) {
nodes {
${METADATA}
summary @optional
userPermissions @optional { resumeDuoWorkflow @optional }
latestCheckpoint @optional {
lastDuoMessage @optional { content role messageType }
}
mergeRequestLinks(linkType: CREATED, first: 20) @optional {
nodes { mergeRequest { id title webUrl } } pageInfo { hasNextPage }
}
workItemLinks(linkType: CREATED, first: 20) @optional {
nodes { workItem { id title webUrl } } pageInfo { hasNextPage }
}
noteLinks(linkType: CREATED, first: 20) @optional {
nodes { note { id url body } } pageInfo { hasNextPage }
}
}
}
}
`;
export const HISTORY: DocumentNode = gql`
query DuoSessionLatestAnswer($id: AiDuoWorkflowsWorkflowID!) {
duoWorkflowWorkflows(workflowId: $id, first: 1) {
nodes {
id
projectId
latestCheckpoint {
duoMessages {
content
role
messageType
}
}
}
}
}
`;
|