Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions apps/hash-api/src/ai/infer-entities-websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { handleInferEntitiesRequest } from "./infer-entities-websocket/handle-in

import type { GraphApi, ImpureGraphContext } from "../graph/context-types";
import type { User } from "../graph/knowledge/system-types/user";
import type { EntityUuid } from "@blockprotocol/type-system";
import type { FileStorageProvider } from "@local/hash-backend-utils/file-storage";
import type { Logger } from "@local/hash-backend-utils/logger";
import type {
Expand Down Expand Up @@ -89,7 +88,7 @@ const inferEntitiesMessageHandler = async ({
for (const inputRequest of flowRun.inputRequests) {
if (!inputRequest.resolvedAt) {
const requestMessage: ExternalInputWebsocketRequestMessage = {
workflowId: flowRun.flowRunId,
flowRunEntityId: flowRun.flowRunEntityId,
payload: inputRequest,
type: "external-input-request",
};
Expand All @@ -100,19 +99,21 @@ const inferEntitiesMessageHandler = async ({
return;
}
case "external-input-response": {
const { workflowId, payload } = message;
const { flowRunEntityId, payload } = message;

const flow = await getFlowRunEntityById({
userAuthentication: { actorId: user.accountId },
flowRunId: workflowId as EntityUuid,
flowRunEntityId,
graphApiClient,
});

if (!flow) {
return;
}

const handle = temporalClient.workflow.getHandle(workflowId);
const handle = temporalClient.workflow.getHandle(
flow.properties["https://hash.ai/@h/types/property-type/workflow-id/"],
);
await handle.signal<[ExternalInputResponseSignal]>(
externalInputResponseSignal,
{ ...payload, resolvedBy: user.accountId },
Expand Down Expand Up @@ -152,15 +153,15 @@ const isInferenceWebsocketClientMessage = (
);
case "cancel-inference-request":
return (
typeof message.flowRunId === "string" &&
typeof message.flowRunEntityId === "string" &&
typeof message.requestUuid === "string" &&
hasValidOptionalCookie(message)
);
case "check-for-external-input-requests":
return hasValidOptionalCookie(message);
case "external-input-response":
return (
typeof message.workflowId === "string" &&
typeof message.flowRunEntityId === "string" &&
typeof message.payload === "object" &&
message.payload !== null &&
hasValidOptionalCookie(message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { getFlowRunEntityById } from "@local/hash-backend-utils/flows";

import type { GraphApi } from "../../graph/context-types";
import type { User } from "../../graph/knowledge/system-types/user";
import type { EntityUuid } from "@blockprotocol/type-system";
import type { CancelInferEntitiesWebsocketRequestMessage } from "@local/hash-isomorphic-utils/ai-inference-types";
import type { Client } from "@temporalio/client";

Expand All @@ -17,19 +16,21 @@ export const handleCancelInferEntitiesRequest = async ({
message: Omit<CancelInferEntitiesWebsocketRequestMessage, "cookie">;
user: User;
}) => {
const { flowRunId } = message;
const { flowRunEntityId } = message;

const flow = await getFlowRunEntityById({
userAuthentication: { actorId: user.accountId },
flowRunId: flowRunId as EntityUuid,
flowRunEntityId,
graphApiClient,
});

if (!flow) {
return;
}

const workflowHandle = temporalClient.workflow.getHandle(flowRunId);
const workflowHandle = temporalClient.workflow.getHandle(
flow.properties["https://hash.ai/@h/types/property-type/workflow-id/"],
);

void workflowHandle.cancel();
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { FlowRunStatus } from "../../graphql/api-types.gen";

import type { User } from "../../graph/knowledge/system-types/user";
import type { EntityUuid } from "@blockprotocol/type-system";
import type { DistributiveOmit } from "@local/advanced-types/distribute";
import type { FileStorageProvider } from "@local/hash-backend-utils/file-storage";
import type { GraphApi } from "@local/hash-graph-client";
Expand Down Expand Up @@ -95,6 +96,8 @@ export const handleInferEntitiesRequest = async ({
},
flowDefinitionId,
flowInputs,
/* So that the run's entity id can be worked out from the request, as the browser plugin does. */
flowRunEntityUuid: requestUuid as EntityUuid,
userAuthentication: { actorId: user.accountId },
webId,
},
Expand Down
12 changes: 7 additions & 5 deletions apps/hash-api/src/graphql/resolvers/flows/cancel-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import * as Error from "../../error";

import type { MutationResetFlowArgs, ResolverFn } from "../../api-types.gen";
import type { LoggedInGraphQLContext } from "../../context";
import type { EntityUuid } from "@blockprotocol/type-system";

export const cancelFlow: ResolverFn<
Promise<boolean>,
Expand All @@ -16,19 +15,22 @@ export const cancelFlow: ResolverFn<
MutationResetFlowArgs
> = async (
_,
{ flowUuid },
{ flowRunEntityId },
{ authentication, dataSources, provenance, temporal, user },
) => {
const flow = await getFlowRunEntityById({
flowRunId: flowUuid as EntityUuid,
flowRunEntityId,
graphApiClient: dataSources.graphApi,
userAuthentication: authentication,
});

if (!flow) {
throw Error.notFound(`Flow with id ${flowUuid} not found`);
throw Error.notFound(`Flow with id ${flowRunEntityId} not found`);
}

const workflowId =
flow.properties["https://hash.ai/@h/types/property-type/workflow-id/"];
Comment thread
CiaranMn marked this conversation as resolved.

const userCanModify = await checkEntityPermission(
{ graphApi: dataSources.graphApi, provenance },
authentication,
Expand All @@ -45,7 +47,7 @@ export const cancelFlow: ResolverFn<
await temporal.workflowService.requestCancelWorkflowExecution({
namespace: temporalNamespace,
workflowExecution: {
workflowId: flowUuid,
workflowId,
},
reason: `Cancelled via GraphQL API by @${user.shortname}`,
requestId: generateUuid(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type {
ResolverFn,
} from "../../api-types.gen";
import type { GraphQLContext } from "../../context";
import type { EntityUuid } from "@blockprotocol/type-system";
import type { SparseFlowRun } from "@local/hash-isomorphic-utils/flows/types";

export const getFlowRunByIdResolver: ResolverFn<
Expand All @@ -18,12 +17,12 @@ export const getFlowRunByIdResolver: ResolverFn<
Pick<GraphQLContext, "authentication" | "dataSources" | "temporal">,
QueryGetFlowRunByIdArgs
> = async (_parent, args, context, info) => {
const { flowRunId } = args;
const { flowRunEntityId } = args;

const includeDetails = wereDetailedFieldsRequested(info);

const flowRun = await getFlowRunById({
flowRunId: flowRunId as EntityUuid,
flowRunEntityId,
graphApiClient: context.dataSources.graphApi,
includeDetails,
storageProvider: context.dataSources.uploadProvider,
Expand All @@ -32,7 +31,7 @@ export const getFlowRunByIdResolver: ResolverFn<
});

if (!flowRun) {
throw Error.notFound(`Flow run with id ${flowRunId} not found`);
throw Error.notFound(`Flow run with id ${flowRunEntityId} not found`);
}

return flowRun;
Expand Down
12 changes: 7 additions & 5 deletions apps/hash-api/src/graphql/resolvers/flows/reset-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import * as Error from "../../error";

import type { MutationResetFlowArgs, ResolverFn } from "../../api-types.gen";
import type { LoggedInGraphQLContext } from "../../context";
import type { EntityUuid } from "@blockprotocol/type-system";

export const resetFlow: ResolverFn<
Promise<boolean>,
Expand All @@ -19,19 +18,22 @@ export const resetFlow: ResolverFn<
MutationResetFlowArgs
> = async (
_,
{ flowUuid, checkpointId, eventId },
{ flowRunEntityId, checkpointId, eventId },
{ authentication, dataSources, provenance, temporal },
) => {
const flow = await getFlowRunEntityById({
flowRunId: flowUuid as EntityUuid,
flowRunEntityId,
graphApiClient: dataSources.graphApi,
userAuthentication: authentication,
});

if (!flow) {
throw Error.notFound(`Flow with id ${flowUuid} not found`);
throw Error.notFound(`Flow with id ${flowRunEntityId} not found`);
}

const workflowId =
flow.properties["https://hash.ai/@h/types/property-type/workflow-id/"];

const userCanModify = await checkEntityPermission(
{ graphApi: dataSources.graphApi, provenance },
authentication,
Expand All @@ -48,7 +50,7 @@ export const resetFlow: ResolverFn<
await temporal.workflowService.resetWorkflowExecution({
namespace: temporalNamespace,
workflowExecution: {
workflowId: flowUuid,
workflowId,
},
/**
* If we don't set this, Temporal will replay signals sent after the cancellation point to the new workflow execution.
Expand Down
9 changes: 5 additions & 4 deletions apps/hash-api/src/graphql/resolvers/flows/start-flow.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { entityIdFromComponents } from "@blockprotocol/type-system";
import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid";

import {
Expand All @@ -9,14 +10,14 @@ import { assertClientFlowInputs } from "./shared/assert-client-flow-inputs";
import { getRunnableFlowDefinition } from "./shared/get-runnable-flow-definition";

import type { LoggedInGraphQLContext } from "../../context";
import type { EntityUuid } from "@blockprotocol/type-system";
import type { EntityId, EntityUuid } from "@blockprotocol/type-system";
import type {
RunFlowWorkflowParams,
RunFlowWorkflowResponse,
} from "@local/hash-isomorphic-utils/flows/temporal-types";

export const startFlow: ResolverFn<
Promise<EntityUuid>,
Promise<EntityId>,
Record<string, never>,
LoggedInGraphQLContext,
MutationStartFlowArgs
Expand Down Expand Up @@ -45,7 +46,7 @@ export const startFlow: ResolverFn<

const params: RunFlowWorkflowParams = {
...(flowType === "ai" ? { dataSources } : {}),
flowRunId: workflowId,
flowRunEntityUuid: workflowId,
flowInputs,
flowDefinitionId,
userAuthentication: { actorId: user.accountId },
Expand All @@ -68,5 +69,5 @@ export const startFlow: ResolverFn<
},
});

return workflowId;
return entityIdFromComponents(webId, workflowId);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type {
ResolverFn,
} from "../../api-types.gen";
import type { LoggedInGraphQLContext } from "../../context";
import type { EntityUuid } from "@blockprotocol/type-system";

export const submitExternalInputResponse: ResolverFn<
Promise<boolean>,
Expand All @@ -17,20 +16,23 @@ export const submitExternalInputResponse: ResolverFn<
MutationSubmitExternalInputResponseArgs
> = async (
_,
{ response, flowUuid },
{ response, flowRunEntityId },
{ authentication, dataSources, temporal },
) => {
const flow = await getFlowRunEntityById({
flowRunId: flowUuid as EntityUuid,
flowRunEntityId,
graphApiClient: dataSources.graphApi,
userAuthentication: authentication,
});

if (!flow) {
throw Error.notFound(`Flow with id ${flowUuid} not found`);
throw Error.notFound(`Flow with id ${flowRunEntityId} not found`);
}

const handle = temporal.workflow.getHandle(flowUuid);
const workflowId =
flow.properties["https://hash.ai/@h/types/property-type/workflow-id/"];

const handle = temporal.workflow.getHandle(workflowId);

await handle.signal(externalInputResponseSignal, response);

Expand Down
12 changes: 8 additions & 4 deletions apps/hash-frontend/src/graphql/queries/knowledge/flow.queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,22 @@ export const startFlowMutation = gql`
`;

export const resetFlowMutation = gql`
mutation resetFlow($flowUuid: ID!, $checkpointId: ID!, $eventId: Int!) {
mutation resetFlow(
$flowRunEntityId: EntityId!
$checkpointId: ID!
$eventId: Int!
) {
resetFlow(
checkpointId: $checkpointId
eventId: $eventId
flowUuid: $flowUuid
flowRunEntityId: $flowRunEntityId
)
}
`;

export const cancelFlowMutation = gql`
mutation cancelFlow($flowUuid: ID!) {
cancelFlow(flowUuid: $flowUuid)
mutation cancelFlow($flowRunEntityId: EntityId!) {
cancelFlow(flowRunEntityId: $flowRunEntityId)
}
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const FlowDefinitionPage: NextPageWithLayout = () => {
<FlowDefinitionsContextProvider
selectedFlowDefinitionId={routeFlowDefinitionId}
>
<FlowRunsContextProvider selectedFlowRunId={null}>
<FlowRunsContextProvider selectedFlowRunEntityId={null}>
<FlowVisualizer />
</FlowRunsContextProvider>
</FlowDefinitionsContextProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,8 @@ export const FlowVisualizer = () => {
try {
const { data } = await startFlow({ variables });

const flowRunId = data?.startFlow;
if (!flowRunId) {
const flowRunEntityId = data?.startFlow;
if (!flowRunEntityId) {
throw new Error("Failed to start flow");
}

Expand All @@ -616,7 +616,7 @@ export const FlowVisualizer = () => {

const { shortname } = getOwner({ webId: variables.webId });

void push(generateWorkerRunPath({ shortname, flowRunId }));
void push(generateWorkerRunPath({ shortname, flowRunEntityId }));
} finally {
setStartFlowPending(false);
}
Expand Down Expand Up @@ -646,7 +646,7 @@ export const FlowVisualizer = () => {

const flowDefinitionStateKey = `${selectedFlowDefinition.name} ?? "loading`;
const flowRunStateKey = `${flowDefinitionStateKey}-${
selectedFlowRun?.flowRunId ?? "definition"
selectedFlowRun?.flowRunEntityId ?? "definition"
}`;

const isRunnableFromHere = !unrunnableDefinitionIds.includes(
Expand Down Expand Up @@ -707,7 +707,7 @@ export const FlowVisualizer = () => {
{selectedFlowRun ? (
<FlowRunSidebar
flowDefinitionId={selectedFlow.flowDefinitionId}
flowRunId={selectedFlowRun.flowRunId}
flowRunEntityId={selectedFlowRun.flowRunEntityId}
flowScheduleId={selectedFlowRun.flowScheduleId ?? null}
graph={graph}
name={selectedFlowRun.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ const Checkpoint = ({ log }: { log: CheckpointLog }) => {

void resetFlow({
variables: {
flowUuid: selectedFlowRun.flowRunId,
flowRunEntityId: selectedFlowRun.flowRunEntityId,
checkpointId: log.checkpointId,
eventId: log.eventId,
},
Expand Down
Loading
Loading