From a55e5f12e82923f8e510c6531ff447518c619d84 Mon Sep 17 00:00:00 2001 From: Bilal Mahmoud <7252775+indietyp@users.noreply.github.com> Date: Sat, 23 May 2026 12:39:29 +0200 Subject: [PATCH 1/2] feat: increase printWidth --- oxfmt.config.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/oxfmt.config.ts b/oxfmt.config.ts index 99290d85b26..835d85408f1 100644 --- a/oxfmt.config.ts +++ b/oxfmt.config.ts @@ -4,7 +4,7 @@ export default defineConfig({ // Indentation and line length useTabs: false, tabWidth: 2, - printWidth: 80, + printWidth: 100, endOfLine: "lf", // Quotes @@ -31,13 +31,7 @@ export default defineConfig({ "value-external", "value-internal", ["value-parent", "value-sibling", "value-index"], - [ - "type-import", - "type-internal", - "type-parent", - "type-sibling", - "type-index", - ], + ["type-import", "type-internal", "type-parent", "type-sibling", "type-index"], "unknown", ], }, From 5bf3cceaa4c0073a1b1a4259a02ccd867933fff5 Mon Sep 17 00:00:00 2001 From: Bilal Mahmoud <7252775+indietyp@users.noreply.github.com> Date: Sat, 23 May 2026 12:40:45 +0200 Subject: [PATCH 2/2] feat: the formatting --- .claude/hooks/skill-activation-prompt.test.ts | 3 +- .claude/hooks/skill-activation-prompt.ts | 62 +- .claude/skills/skill-rules.json | 25 +- .../references/testing-strategies.md | 8 +- .../references/special-forms.md | 7 +- .../references/syntax-reference.md | 5 +- .config/_examples/vscode/settings.json | 7 +- .config/_examples/zed/settings.json | 7 +- .config/agents/rules/zod.md | 5 +- .../scripts/compare-llm-response.ts | 14 +- .../scripts/sanitize-html.ts | 4 +- apps/hash-ai-worker-ts/src/activities.ts | 107 +- .../src/activities/flow-activities.ts | 14 +- .../flow-activities/answer-question-action.ts | 49 +- .../generate-flow-run-name-activity.ts | 28 +- .../generate-web-queries-action.ts | 9 +- .../get-file-from-url-action.ts | 4 +- .../get-web-page-by-url-action.ts | 6 +- .../get-web-page-summary-action.ai.test.ts | 7 +- .../get-web-page-summary-action.ts | 13 +- .../infer-entities-from-content-action.ts | 41 +- .../infer-metadata-from-document-action.ts | 31 +- .../generate-property-patches.ts | 3 +- .../generate-proposed-entities-and-claims.ts | 63 +- .../get-llm-analysis-of-doc.ts | 156 +- .../persist-entities-action.ts | 87 +- .../flow-activities/persist-entity-action.ts | 64 +- ...cess-automatic-browsing-settings-action.ts | 30 +- .../research-entities-action.ai.test.ts | 41 +- .../research-entities-action.ts | 15 +- .../research-entities-action/checkpoints.ts | 23 +- .../coordinating-agent.ts | 89 +- .../check-delegated-tasks-agent.ai.test.ts | 147 +- .../check-delegated-tasks-agent.ts | 25 +- .../coordinating-agent/create-initial-plan.ts | 51 +- .../coordinating-agent/generate-messages.ts | 41 +- .../process-complete-tool-call.ts | 24 +- .../request-coordinator-actions.ts | 29 +- .../summarize-existing-entities.ai.test.ts | 7 +- .../summarize-existing-entities.ts | 19 +- .../update-state-from-inferred-claims.ts | 131 +- .../get-answers-from-human.ts | 8 +- .../link-follower-agent.ai.test.ts | 40 +- .../link-follower-agent.ts | 145 +- ...ant-links-from-content.optimize.ai.test.ts | 18 +- .../choose-relevant-links-from-content.ts | 24 +- .../filter-and-rank-text-chunks-agent.ts | 31 +- .../get-link-follower-next-tool-calls.ts | 44 +- .../llama-index/index-pdf-file.ts | 13 +- .../llama-index/simple-storage-context.ts | 4 +- .../shared/check-if-worker-should-stop.ts | 14 +- .../shared/coordinator-tools.ts | 56 +- .../get-tool-call-results.ts | 41 +- .../shared/coordinators.ts | 14 +- .../shared/deduplicate-claims.ts | 23 +- .../shared/deduplicate-entities.ai.test.ts | 119 +- .../shared/deduplicate-entities.ts | 22 +- .../shared/handle-web-search-tool-call.ts | 18 +- ...vious-coordinator-calls-to-llm-messages.ts | 4 +- .../simplify-for-llm-consumption.ai.test.ts | 4 +- .../shared/simplify-for-llm-consumption.ts | 20 +- .../sub-coordinating-agent.ai.test.ts | 25 +- .../sub-coordinating-agent.ts | 90 +- .../create-initial-plan.ts | 20 +- .../generate-messages.ts | 23 +- .../request-sub-coordinator-actions.ts | 16 +- .../sub-coordinating-agent/state.ts | 5 +- .../sub-coordinator-tools.ts | 7 +- .../flow-activities/shared/claims.ts | 4 +- .../shared/create-file-entity-from-url.ts | 131 +- .../flow-activities/shared/graph-requests.ts | 19 +- .../infer-summaries-then-claims-from-text.ts | 62 +- .../get-entity-summaries-from-text.ai.test.ts | 16 +- ...ty-summaries-from-text.optimize.ai.test.ts | 47 +- .../test-data.ts | 33 +- .../get-entity-summaries-from-text.ts | 27 +- .../infer-entity-claims-from-text-agent.ts | 130 +- .../infer-entity-claims-from-text.ai.test.ts | 24 +- ...summaries-then-claims-from-text.ai.test.ts | 122 +- .../shared/propose-entities-from-claims.ts | 47 +- .../propose-entities-from-claims.ai.test.ts | 321 +--- .../propose-entity-from-claims-agent.ts | 146 +- .../propose-entity-from-claims.ai.test.ts | 60 +- .../flow-activities/web-search-action.ts | 8 +- .../write-google-sheet-action.ts | 107 +- .../convert-csv-to-sheet-requests.ts | 4 +- .../convert-subgraph-to-sheet-requests.ts | 97 +- .../get-filter-from-bp-query-entity.ts | 4 +- .../get-subgraph-from-filter.ts | 6 +- .../get-ai-assistant-account-id-activity.ts | 15 +- .../get-dereferenced-entity-types-activity.ts | 4 +- .../get-web-page-activity.ai.test.ts | 5 +- .../src/activities/get-web-page-activity.ts | 53 +- .../get-web-search-results-activity.ts | 4 +- .../hash-ai-worker-ts/src/activities/graph.ts | 88 +- .../infer-entities-from-web-page-activity.ts | 8 +- .../infer-entity-summaries-from-web-page.ts | 9 +- .../infer-entities/infer-entity-summaries.ts | 58 +- .../generate-summary-tools.ts | 29 +- .../infer-entities/inference-types.ts | 10 +- .../generate-persist-entities-tools.ts | 20 +- .../infer-entities/propose-entities.ts | 338 ++-- .../extract-validation-failure-details.ts | 3 +- .../shared/generate-propose-entities-tools.ts | 98 +- .../shared/generate-simplified-type-id.ts | 12 +- ...map-simplified-properties-to-properties.ts | 11 +- .../strip-ids-from-dereferenced-properties.ts | 5 +- .../src/activities/parse-text-from-file.ts | 26 +- .../src/activities/shared/activity-logger.ts | 8 +- .../create-inferred-entity-notification.ts | 7 +- .../shared/dereference-entity-type.test.ts | 115 +- .../shared/dereference-entity-type.ts | 215 +-- .../src/activities/shared/embeddings.ts | 4 +- .../activities/shared/find-existing-entity.ts | 89 +- .../src/activities/shared/get-flow-context.ts | 48 +- .../src/activities/shared/get-llm-response.ts | 13 +- .../get-llm-response/anthropic-client.ts | 36 +- .../check-web-service-usage-not-exceeded.ts | 11 +- .../get-anthropic-response.ts | 90 +- .../get-google-ai-response.ts | 24 +- .../google-cloud-storage.ts | 29 +- .../map-google-messages-to-llm-messages.ts | 4 +- .../map-parts-and-upload-files.ts | 51 +- .../rewrite-schema-for-google.ts | 30 +- .../get-llm-response/get-openai-reponse.ts | 75 +- .../google-vertex-ai-client.ts | 22 +- .../shared/get-llm-response/llm-message.ts | 242 ++- .../get-llm-response/log-llm-request.ts | 4 +- .../shared/get-llm-response/types.ts | 101 +- .../shared/get-llm-response/validation.ts | 15 +- .../judge-test-data.ts | 110 +- .../judge-ai-output.optimize.ai.test.ts | 256 ++- .../src/activities/shared/judge-ai-outputs.ts | 29 +- .../src/activities/shared/log-progress.ts | 6 +- .../map-action-input-entities-to-entities.ts | 14 +- .../match-existing-entity.optimize.ai.test.ts | 224 +-- .../shared/match-existing-entity.ts | 38 +- .../src/activities/shared/openai-client.ts | 7 +- .../shared/optimize-system-prompt.ts | 106 +- .../improve-system-prompt.ts | 79 +- .../shared/request-external-input.ts | 4 +- .../src/activities/shared/stringify.ts | 4 +- .../shared/use-file-system-file-from-url.ts | 22 +- apps/hash-ai-worker-ts/src/instrument.ts | 5 +- apps/hash-ai-worker-ts/src/main.ts | 3 +- apps/hash-ai-worker-ts/src/shared/queries.ts | 5 +- apps/hash-ai-worker-ts/src/shared/signals.ts | 12 +- .../get-alice-user-account-id.ts | 21 +- .../mock-get-flow-context.ts | 10 +- apps/hash-ai-worker-ts/src/workflows.ts | 75 +- .../src/workflows/run-flow-workflow.ts | 18 +- .../set-query-and-signal-handlers.ts | 66 +- apps/hash-ai-worker-ts/vitest.config.ts | 5 +- apps/hash-api/codegen.config.ts | 7 +- apps/hash-api/eslint.config.js | 6 +- apps/hash-api/public/consent.js | 4 +- .../src/ai/gpt/generate-hashgpt-schema.ts | 54 +- apps/hash-api/src/ai/gpt/gpt-get-user-webs.ts | 6 +- .../hash-api/src/ai/gpt/gpt-query-entities.ts | 54 +- apps/hash-api/src/ai/gpt/gpt-query-types.ts | 128 +- .../src/ai/gpt/upsert-gpt-oauth-client.ts | 12 +- .../src/ai/infer-entities-websocket.ts | 13 +- .../handle-infer-entities-request.ts | 11 +- .../hash-api/src/auth/create-auth-handlers.ts | 32 +- .../create-unverified-email-cleanup-job.ts | 54 +- .../src/auth/oauth-consent-handlers.ts | 31 +- apps/hash-api/src/auth/ory-kratos.ts | 50 +- .../src/email/create-email-transporter.ts | 10 +- .../transporters/aws-ses-email-transporter.ts | 5 +- .../transporters/dummy-email-transporter.ts | 5 +- .../transporters/smtp-email-transporter.ts | 5 +- .../src/generate-ontology-type-ids.ts | 74 +- apps/hash-api/src/graph/context-types.ts | 4 +- .../migrate-ontology-types.ts | 29 +- ...reate-first-custom-data-types.migration.ts | 343 ++-- .../001-create-hash-system-types.migration.ts | 1565 ++++++++--------- ...03-create-linear-system-types.migration.ts | 1376 +++++++-------- ...-create-machines-update-users.migration.ts | 110 +- ...-system-entities-and-web-bots.migration.ts | 26 +- ...007-create-api-usage-tracking.migration.ts | 163 +- ...-plugin-settings-update-users.migration.ts | 117 +- ...ad-completed-at-property-type.migration.ts | 40 +- .../010-create-office-file-types.migration.ts | 159 +- .../011-deprecate-preferred-name.migration.ts | 70 +- ...te-google-sheets-system-types.migration.ts | 148 +- ...nabled-feature-flags-property.migration.ts | 43 +- ...use-case-form-and-example-org.migration.ts | 57 +- ...lication-preferences-property.migration.ts | 40 +- ...-doc-company-and-person-types.migration.ts | 494 +++--- ...0-add-integration-parent-type.migration.ts | 51 +- .../021-add-org-invites.migration.ts | 66 +- ...ns-completed-to-hash-instance.migration.ts | 83 +- ...create-more-custom-data-types.migration.ts | 64 +- .../024-add-flow-types.migration.ts | 720 ++++---- ...086-add-study-record-type.dev.migration.ts | 401 ++--- ...itial-currency-data-types.dev.migration.ts | 34 +- .../090-add-aviation-types.dev.migration.ts | 1066 +++++------ .../091-add-petri-nets.dev.migration.ts | 61 +- .../migrate-ontology-types/util.ts | 291 +-- .../util/upgrade-entities.ts | 117 +- .../util/upgrade-entity-type-dependencies.ts | 66 +- .../system-webs-and-entities.ts | 116 +- .../src/graph/knowledge/primitive/entity.ts | 152 +- .../entity/after-create-entity-hooks.ts | 100 +- ...ument-after-update-entity-hook-callback.ts | 69 +- .../text-after-update-entity-hook-callback.ts | 241 ++- .../user-after-update-entity-hook.ts | 94 +- ...user-before-update-entity-hook-callback.ts | 279 ++- .../primitive/entity/create-entity-hooks.ts | 5 +- .../entity/shared/mention-notification.ts | 35 +- .../primitive/entity/update-entity-hooks.ts | 5 +- .../graph/knowledge/primitive/link-entity.ts | 45 +- .../knowledge/system-types/account.fields.ts | 19 +- .../system-types/block-collection.ts | 97 +- .../src/graph/knowledge/system-types/block.ts | 121 +- .../graph/knowledge/system-types/comment.ts | 88 +- .../src/graph/knowledge/system-types/file.ts | 308 ++-- .../knowledge/system-types/flow-schedule.ts | 218 +-- .../knowledge/system-types/hash-instance.ts | 66 +- .../system-types/linear-integration-entity.ts | 142 +- .../system-types/linear-user-secret.ts | 154 +- .../knowledge/system-types/notification.ts | 267 ++- .../knowledge/system-types/org-membership.ts | 16 +- .../src/graph/knowledge/system-types/org.ts | 69 +- .../src/graph/knowledge/system-types/page.ts | 108 +- .../src/graph/knowledge/system-types/text.ts | 155 +- .../knowledge/system-types/user-secret.ts | 67 +- .../src/graph/knowledge/system-types/user.ts | 187 +- .../src/graph/ontology/primitive/data-type.ts | 31 +- .../graph/ontology/primitive/entity-type.ts | 69 +- .../graph/ontology/primitive/property-type.ts | 38 +- .../src/graph/ontology/primitive/util.ts | 24 +- .../src/graphql/create-apollo-server.ts | 10 +- apps/hash-api/src/graphql/error.ts | 42 +- .../resolvers/blockprotocol/get-block.ts | 8 +- .../src/graphql/resolvers/embed/index.ts | 33 +- .../graphql/resolvers/flows/cancel-flow.ts | 6 +- .../graphql/resolvers/flows/flow-schedule.ts | 74 +- .../resolvers/flows/get-flow-run-by-id.ts | 6 +- .../graphql/resolvers/flows/get-flow-runs.ts | 6 +- .../src/graphql/resolvers/flows/reset-flow.ts | 3 +- .../shared/were-detailed-fields-requested.ts | 9 +- .../src/graphql/resolvers/flows/start-flow.ts | 11 +- .../flows/submit-external-input-response.ts | 11 +- .../resolvers/generation/generate-inverse.ts | 4 +- .../generation/is-generation-available.ts | 5 +- apps/hash-api/src/graphql/resolvers/index.ts | 86 +- .../linear/linear-organization.ts | 18 +- .../sync-linear-integration-with-webs.ts | 66 +- .../block-collection-contents.ts | 16 +- .../update-block-collection-actions.ts | 66 +- .../update-block-collection-contents.ts | 6 +- .../resolvers/knowledge/block/block.ts | 4 +- .../resolvers/knowledge/block/data-entity.ts | 9 +- .../resolvers/knowledge/comment/comment.ts | 5 +- .../resolvers/knowledge/comment/delete.ts | 10 +- .../resolvers/knowledge/comment/resolve.ts | 10 +- .../knowledge/comment/update-text.ts | 5 +- .../resolvers/knowledge/entity/entity.ts | 42 +- .../knowledge/file/create-file-from-url.ts | 13 +- .../knowledge/file/request-file-upload.ts | 33 +- .../resolvers/knowledge/file/shared.ts | 7 +- .../resolvers/knowledge/graphql-mapping.ts | 10 +- .../knowledge/org/accept-org-invitation.ts | 81 +- .../knowledge/org/decline-org-invitation.ts | 10 +- .../get-pending-invitation-by-entity-id.ts | 5 +- .../knowledge/org/invite-user-to-org.ts | 187 +- .../knowledge/org/remove-user-from-org.ts | 6 +- .../graphql/resolvers/knowledge/org/shared.ts | 47 +- .../resolvers/knowledge/page/page-contents.ts | 4 +- .../graphql/resolvers/knowledge/page/page.ts | 26 +- .../knowledge/page/set-parent-page.ts | 17 +- .../resolvers/knowledge/page/update-page.ts | 33 +- .../get-user-permissions-on-subgraph.ts | 11 +- .../knowledge/user/get-usage-records.ts | 22 +- .../knowledge/user/get-waitlist-position.ts | 4 +- .../knowledge/user/is-shortname-taken.ts | 5 +- .../user/submit-early-access-form.ts | 35 +- .../resolvers/middlewares/middleware-types.ts | 6 +- .../resolvers/middlewares/signed-up.ts | 4 +- .../graphql/resolvers/ontology/data-type.ts | 11 +- .../graphql/resolvers/ontology/entity-type.ts | 6 +- .../resolvers/ontology/property-type.ts | 12 +- apps/hash-api/src/index.ts | 98 +- apps/hash-api/src/instrument.mjs | 10 +- .../src/integrations/enabled-integrations.ts | 4 +- .../src/integrations/google/oauth-callback.ts | 35 +- apps/hash-api/src/integrations/linear.ts | 31 +- .../hash-api/src/integrations/linear/oauth.ts | 75 +- .../src/integrations/linear/sync-back.ts | 50 +- .../src/integrations/linear/webhook.ts | 35 +- apps/hash-api/src/lib/config.ts | 11 +- apps/hash-api/src/lib/env-config.ts | 3 +- apps/hash-api/src/mailchimp.ts | 10 +- apps/hash-api/src/seed-data/index.ts | 33 +- .../src/seed-data/seed-flow-test-types.ts | 787 ++++----- apps/hash-api/src/seed-data/seed-pages.ts | 13 +- apps/hash-api/src/seed-data/seed-users.ts | 8 +- .../src/shared/user-has-access-to-hash.ts | 23 +- apps/hash-api/src/storage/index.ts | 112 +- .../src/storage/local-file-storage.ts | 20 +- apps/hash-api/src/telemetry/rudderstack.ts | 3 +- apps/hash-api/src/telemetry/snowplow-setup.ts | 9 +- apps/hash-api/src/util.test.ts | 13 +- apps/hash-api/src/util.ts | 4 +- apps/hash-api/views/consent.hbs | 24 +- .../docker-compose.dev.yml | 3 +- .../docker-compose.prod.yml | 9 +- .../docker-compose.test.yml | 6 +- .../hash-external-services/docker-compose.yml | 14 +- apps/hash-frontend/buildstamp.js | 3 +- apps/hash-frontend/codegen.config.ts | 3 +- apps/hash-frontend/eslint.config.js | 9 +- apps/hash-frontend/instrumentation-client.ts | 4 +- apps/hash-frontend/next.config.js | 15 +- .../src/blocks/on-block-loaded.tsx | 39 +- .../src/blocks/use-fetch-block-subgraph.ts | 19 +- apps/hash-frontend/src/blocks/user-blocks.tsx | 21 +- .../components/block-loader/block-loader.tsx | 132 +- .../block-loader/fetch-embed-code.ts | 5 +- .../src/components/confirmation-alert.tsx | 4 +- .../components/dropdowns/version-dropdown.tsx | 4 +- .../components/error-block/error-block.tsx | 8 +- .../src/components/forms/select-input.tsx | 17 +- .../src/components/forms/tags-input.tsx | 6 +- .../src/components/forms/text-input.tsx | 4 +- .../src/components/grid/grid.tsx | 153 +- .../src/components/grid/utils.ts | 7 +- .../grid/utils/column-filter-menu.tsx | 57 +- .../components/grid/utils/conversion-menu.tsx | 18 +- .../grid/utils/draw-chip-with-icon.ts | 47 +- .../grid/utils/draw-chip-with-text.ts | 8 +- .../grid/utils/draw-text-with-icon.ts | 13 +- .../grid/utils/interactable-manager.ts | 24 +- .../grid/utils/interactable-manager/utils.ts | 22 +- .../grid/utils/override-custom-renderers.tsx | 75 +- .../src/components/grid/utils/sorting.ts | 3 +- .../components/grid/utils/use-draw-header.ts | 68 +- .../grid/utils/use-grid-tooltip.tsx | 12 +- .../draw-interactable-tooltip-icons.ts | 4 +- .../knowledge/knowledge-shim.ts | 7 +- .../use-block-protocol-archive-entity.ts | 7 +- .../use-block-protocol-create-entity.ts | 45 +- .../use-block-protocol-file-upload.ts | 3 +- .../use-block-protocol-get-entity.ts | 4 +- .../use-block-protocol-query-entities.ts | 16 +- .../use-block-protocol-update-entity.ts | 7 +- .../use-block-protocol-create-entity-type.ts | 7 +- ...use-block-protocol-create-property-type.ts | 7 +- .../use-block-protocol-get-data-type.ts | 19 +- .../use-block-protocol-get-entity-type.ts | 31 +- .../use-block-protocol-get-property-type.ts | 10 +- .../use-block-protocol-query-data-types.ts | 17 +- .../use-block-protocol-query-entity-types.ts | 5 +- ...use-block-protocol-query-property-types.ts | 5 +- .../use-block-protocol-update-entity-type.ts | 7 +- ...use-block-protocol-update-property-type.ts | 7 +- .../src/components/hooks/use-account-pages.ts | 14 +- .../src/components/hooks/use-archive-page.ts | 17 +- .../src/components/hooks/use-create-page.ts | 17 +- .../components/hooks/use-create-sub-page.ts | 16 +- .../components/hooks/use-default-state.tsx | 16 +- .../src/components/hooks/use-entity-by-id.ts | 65 +- .../hooks/use-font-loaded-callback.ts | 5 +- .../hooks/use-get-account-id-for-shortname.ts | 16 +- .../hooks/use-get-block-protocol-blocks.ts | 5 +- .../hooks/use-get-owner-for-entity.ts | 8 +- .../src/components/hooks/use-hash-instance.ts | 4 +- .../src/components/hooks/use-logout-flow.ts | 3 +- .../components/hooks/use-orgs-with-links.ts | 11 +- .../src/components/hooks/use-orgs.ts | 59 +- .../src/components/hooks/use-page-comments.ts | 22 +- .../src/components/hooks/use-reorder-page.ts | 4 +- .../components/hooks/use-shortname-input.ts | 19 +- .../src/components/hooks/use-snackbar.ts | 25 +- .../hooks/use-update-authenticated-user.ts | 16 +- .../components/hooks/use-update-page-title.ts | 5 +- ...se-user-or-org-shortname-by-owned-by-id.ts | 4 +- .../components/hooks/use-users-with-links.ts | 7 +- .../src/components/hooks/use-users.ts | 62 +- .../src/components/page-icon.tsx | 7 +- .../remote-block/add-linked-query-prompt.tsx | 10 +- .../remote-block/block-renderer.tsx | 9 +- .../block-renderer/custom-element.tsx | 20 +- .../remote-block/block-renderer/html.tsx | 4 +- .../construct-service-module-callbacks.ts | 3 +- .../remote-block/load-remote-block.ts | 23 +- .../components/remote-block/remote-block.tsx | 22 +- .../remote-block/use-remote-block.ts | 38 +- .../sandbox/block-framer/block-framer.tsx | 9 +- .../sandbox/framed-block/framed-block.tsx | 26 +- .../components/sandbox/framed-block/util.ts | 6 +- .../resizing-iframe/resizing-iframe.tsx | 73 +- .../src/graphql/queries/comment.queries.ts | 15 +- .../queries/knowledge/entity.queries.ts | 36 +- .../graphql/queries/knowledge/flow.queries.ts | 6 +- .../graphql/queries/knowledge/org.queries.ts | 12 +- .../queries/ontology/data-type.queries.ts | 12 +- .../queries/ontology/entity-type.queries.ts | 10 +- .../queries/ontology/property-type.queries.ts | 10 +- .../src/graphql/queries/page.queries.ts | 5 +- apps/hash-frontend/src/lib/routes.ts | 4 +- apps/hash-frontend/src/lib/typeguards.ts | 4 +- apps/hash-frontend/src/lib/user-and-org.ts | 112 +- apps/hash-frontend/src/middleware.page.ts | 30 +- .../src/middleware/return-types-as-json.ts | 30 +- .../src/pages/@/[shortname].page.tsx | 73 +- .../edit-pinned-entity-types-modal.tsx | 61 +- .../service-accounts-input.tsx | 26 +- .../user-profile-info-form.tsx | 63 +- .../user-profile-info-modal-header.tsx | 117 +- .../pinned-entity-type-tab-contents.tsx | 49 +- .../pages/@/[shortname].page/profile-bio.tsx | 34 +- .../[shortname].page/profile-page-content.tsx | 10 +- .../[shortname].page/profile-page-header.tsx | 22 +- .../@/[shortname].page/profile-page-info.tsx | 104 +- .../@/[shortname].page/profile-page-tabs.tsx | 19 +- .../pages/@/[shortname].page/profile-tab.tsx | 6 +- .../pages/@/[shortname].page/types-tab.tsx | 6 +- .../src/pages/@/[shortname].page/util.ts | 13 +- .../pages/@/[shortname]/[page-slug].page.tsx | 63 +- .../[page-slug].page/canvas-page.tsx | 12 +- .../canvas-page/block-creation-dialog.tsx | 37 +- .../canvas-page/block-shape.tsx | 29 +- .../canvas-page/locked-canvas.tsx | 17 +- .../entities/[entity-uuid].page.tsx | 17 +- .../[entity-uuid].page/create-entity-page.tsx | 84 +- .../select-entity-type-page.tsx | 18 +- .../[shortname]/flows/[flow-def-id].page.tsx | 4 +- .../[shortname]/shared/archive-menu-item.tsx | 20 +- .../@/[shortname]/shared/flow-visualizer.tsx | 135 +- .../shared/flow-visualizer/activity-log.tsx | 145 +- .../shared/flow-visualizer/dag-slide.tsx | 32 +- .../shared/flow-visualizer/dag.tsx | 21 +- .../flow-visualizer/flow-run-sidebar.tsx | 34 +- .../flow-run-sidebar/group-status.tsx | 10 +- .../group-status/group-step-status.tsx | 25 +- .../flow-run-sidebar/manager.tsx | 64 +- .../manager/resolved-questions-modal.tsx | 8 +- .../shared/flow-visualizer/outputs.tsx | 139 +- .../flow-visualizer/outputs/claims-output.tsx | 14 +- .../flow-visualizer/outputs/deliverables.tsx | 6 +- .../outputs/deliverables/markdown.tsx | 15 +- .../outputs/deliverables/spreadsheet.tsx | 15 +- .../outputs/entity-result-graph.tsx | 9 +- .../outputs/entity-result-table.tsx | 239 +-- .../outputs/entity-result-table/cells.tsx | 14 +- .../outputs/shared/empty-output-box.tsx | 6 +- .../outputs/shared/output-container.tsx | 4 +- .../shared/flow-visualizer/run-flow-modal.tsx | 30 +- .../run-flow-modal/manual-trigger-input.tsx | 27 +- .../flow-visualizer/run-flow-modal/types.ts | 4 +- .../shared/format-time-taken.tsx | 5 +- .../flow-visualizer/shared/question-modal.tsx | 14 +- .../shared/flow-visualizer/shared/types.ts | 3 +- .../shared/flow-visualizer/sort-graph.ts | 108 +- .../shared/flow-visualizer/swimlane.tsx | 32 +- .../flow-visualizer/swimlane/custom-edge.tsx | 4 +- .../flow-visualizer/swimlane/custom-node.tsx | 27 +- .../swimlane/custom-node/handles.tsx | 34 +- .../swimlane/custom-node/node-container.tsx | 14 +- .../shared/flow-visualizer/topbar.tsx | 42 +- .../shared/section-empty-state.tsx | 10 +- .../shared/use-update-profile-avatar.tsx | 26 +- .../[...slug-maybe-version].page.tsx | 42 +- .../[...slug-maybe-version].page.tsx | 42 +- .../types/shared/get-type-base-url.ts | 8 +- .../@/[shortname]/workers/[run-id].page.tsx | 10 +- apps/hash-frontend/src/pages/_app.page.tsx | 24 +- .../src/pages/_app.page/error-fallback.tsx | 16 +- .../src/pages/_document.page.tsx | 4 +- apps/hash-frontend/src/pages/actions.page.tsx | 107 +- .../draft-entities-bulk-actions-dropdown.tsx | 138 +- .../actions.page/draft-entities-context.tsx | 81 +- .../src/pages/actions.page/draft-entities.tsx | 152 +- .../draft-entities-context-bar.tsx | 33 +- .../draft-entities/draft-entities-filters.tsx | 197 +-- .../draft-entities-filters/filter-section.tsx | 45 +- .../actions.page/draft-entities/types.ts | 5 +- .../src/pages/actions.page/draft-entity.tsx | 17 +- .../draft-entity/draft-entity-provenance.tsx | 4 +- .../draft-entity/draft-entity-type.tsx | 13 +- .../draft-entity/draft-entity-viewers.tsx | 35 +- .../draft-entity/draft-entity-web.tsx | 4 +- .../src/pages/admin/admin-page-layout.tsx | 20 +- .../src/pages/admin/users.page.tsx | 110 +- .../admin/users/[user-entity-uuid].page.tsx | 13 +- .../pages/admin/users/basic-info-section.tsx | 22 +- .../src/pages/change-password.page.tsx | 21 +- .../hash-frontend/src/pages/entities.page.tsx | 72 +- apps/hash-frontend/src/pages/flows.page.tsx | 34 +- .../src/pages/goals.page/goals-list.tsx | 3 +- .../goals-list/goal-list-section.tsx | 19 +- .../goals-list/goal-list-section/goal-row.tsx | 36 +- .../src/pages/goals/new.page.tsx | 91 +- .../goals/new.page/deliverable-settings.tsx | 30 +- .../pages/goals/new.page/file-settings.tsx | 47 +- .../goals/new.page/internet-settings.tsx | 24 +- apps/hash-frontend/src/pages/index.page.tsx | 16 +- .../src/pages/index.page/logged-in.tsx | 26 +- .../src/pages/index.page/logged-out.tsx | 26 +- .../index.page/shared/follow-us-button.tsx | 4 +- .../pages/index.page/shared/guide-card.tsx | 11 +- .../pages/index.page/shared/homepage-card.tsx | 9 +- .../pages/index.page/shared/homepage-grid.tsx | 6 +- .../pages/index.page/shared/typography.tsx | 10 +- .../src/pages/index.page/shared/uses-card.tsx | 7 +- .../src/pages/index.page/waitlisted.tsx | 64 +- .../waitlisted/early-access-modal.tsx | 69 +- apps/hash-frontend/src/pages/invites.page.tsx | 7 +- .../src/pages/invites.page/invites-table.tsx | 17 +- .../src/pages/maintenance.page.tsx | 23 +- .../src/pages/new/entity.page.tsx | 30 +- .../src/pages/new/types/data-type.page.tsx | 7 +- .../src/pages/new/types/entity-type.page.tsx | 10 +- .../types/shared/new-type-page-container.tsx | 13 +- apps/hash-frontend/src/pages/notes.page.tsx | 34 +- .../convert-quick-note-to-page-modal.tsx | 47 +- .../pages/notes.page/create-quick-note.tsx | 11 +- .../pages/notes.page/editable-quick-note.tsx | 123 +- .../timestamp-collection-subheading.tsx | 12 +- .../src/pages/notes.page/timestamp-column.tsx | 19 +- .../src/pages/notes.page/today-section.tsx | 183 +- .../src/pages/notifications.page.tsx | 7 +- .../notifications-table.tsx | 48 +- .../notifications-with-links-context.tsx | 666 ++++--- .../use-process-save-and-load.tsx | 44 +- .../use-persisted-nets.ts | 57 +- .../hash-frontend/src/pages/recovery.page.tsx | 53 +- .../src/pages/settings/integrations.page.tsx | 27 +- .../integrations/google-sheets.page.tsx | 8 +- .../create-or-edit-sheets-sync.tsx | 34 +- .../settings/integrations/linear.page.tsx | 40 +- .../settings/integrations/linear/new.page.tsx | 51 +- .../linear/select-linear-teams-table.tsx | 194 +- .../linear/use-linear-integrations.ts | 22 +- .../user-connected-integrations.tsx | 16 +- .../integration-context-menu.tsx | 12 +- .../[shortname]/general.page.tsx | 15 +- .../[shortname]/integrations.page.tsx | 149 +- .../org-integrations-context-menu.tsx | 13 +- .../[shortname]/members.page.tsx | 11 +- .../members.page/add-member-form.tsx | 20 +- .../[shortname]/members.page/member-row.tsx | 14 +- .../member-row/member-context-menu.tsx | 15 +- .../pending-invitations-table.tsx | 23 +- .../settings/organizations/index.page.tsx | 13 +- .../index.page/org-row/org-context-menu.tsx | 10 +- .../new/index.page/create-org-form.tsx | 5 +- .../organizations/shared/org-form.tsx | 48 +- .../pages/settings/personalization.page.tsx | 12 +- .../src/pages/settings/security.page.tsx | 127 +- .../src/pages/settings/shared/image-field.tsx | 8 +- .../shared/settings-page-container.tsx | 15 +- .../src/pages/shared/_app.util.ts | 6 +- .../shared/accept-draft-entity-button.tsx | 56 +- .../src/pages/shared/auth-info-context.tsx | 132 +- .../src/pages/shared/auth-utils.ts | 4 +- .../pages/shared/block-collection-contents.ts | 31 +- .../pages/shared/block-collection-context.tsx | 12 +- .../block-collection/block-collection.tsx | 10 +- .../block-config-menu/block-config-menu.tsx | 39 +- .../block-context-menu-item.tsx | 25 +- .../block-context-menu/block-context-menu.tsx | 52 +- .../block-list-menu-content.tsx | 8 +- .../block-context-menu/block-loader-input.tsx | 22 +- .../block-select-data-modal.tsx | 56 +- .../load-entity-menu-content.tsx | 28 +- .../shared/block-collection/block-context.tsx | 19 +- .../shared/block-collection/block-handle.tsx | 13 +- .../block-collection/block-highlight.tsx | 11 +- .../shared/block-collection/block-portals.tsx | 8 +- .../shared/block-collection/block-view.tsx | 47 +- .../clipboard-text-serializer.ts | 22 +- .../collab-position-indicator.tsx | 8 +- .../collab-position-indicators.tsx | 19 +- .../collab/editor-connection.ts | 33 +- .../shared/block-collection/collab/http.ts | 17 +- .../collab/use-collab-positions.ts | 16 +- .../comments/comment-action-buttons.tsx | 4 +- .../comments/comment-block-menu-item.tsx | 8 +- .../comments/comment-block.tsx | 51 +- .../comments/comment-placeholder-plugin.tsx | 3 +- .../comments/comment-text-field.tsx | 19 +- .../comments/comment-thread.tsx | 30 +- .../comments/create-block-comment-button.tsx | 17 +- .../block-collection/component-view.tsx | 54 +- .../block-collection/create-editor-view.ts | 3 +- .../block-collection/create-error-plugin.tsx | 4 +- .../create-format-plugins/index.tsx | 21 +- .../create-format-plugins/link-modal.tsx | 3 +- .../create-format-plugins/marks-tooltip.tsx | 5 +- .../create-format-plugins/util.ts | 6 +- .../create-placeholder-plugin.tsx | 26 +- .../create-placeholder-plugin/placeholder.tsx | 3 +- .../create-suggester/block-suggester.tsx | 8 +- .../create-suggester/create-suggester.tsx | 51 +- .../create-suggester/suggester.tsx | 18 +- .../create-text-editor-view.ts | 4 +- .../focus-page-title-plugin.ts | 4 +- .../shared/block-collection/insert-block.tsx | 8 +- .../mention-view/mention-display.tsx | 56 +- .../mention-view/mention-node-view.ts | 8 +- .../shared/block-collection/page-context.tsx | 7 +- .../page-title/page-title.tsx | 23 +- .../block-collection/page-title/utils.ts | 7 +- .../shared/mention-suggester.tsx | 163 +- .../mention-suggester-entity.tsx | 32 +- .../mention-suggester-subheading.tsx | 5 +- .../shared/use-filtered-blocks.tsx | 15 +- .../shared/block-collection/style.module.css | 4 +- .../src/pages/shared/breadcrumbs.tsx | 19 +- .../src/pages/shared/claims-table.tsx | 120 +- .../pages/shared/create-data-type-form.tsx | 41 +- .../pages/shared/create-entity-type-form.tsx | 72 +- .../src/pages/shared/data-type.tsx | 76 +- .../data-type/data-type-constraints.tsx | 25 +- .../abstract-constraint.tsx | 12 +- .../number-constraints.tsx | 89 +- .../shared/constraint-text.tsx | 8 +- .../shared/enum-editor.tsx | 53 +- .../string-constraints.tsx | 56 +- .../data-type/data-type-conversions.tsx | 71 +- .../conversion-editor.tsx | 17 +- .../conversion-target-editor.tsx | 53 +- .../pages/shared/data-type/data-type-form.tsx | 26 +- .../shared/data-type/data-type-header.tsx | 35 +- .../data-type-description.tsx | 4 +- .../shared/data-type/data-type-labels.tsx | 10 +- .../shared/data-type/data-type-parents.tsx | 59 +- .../shared/data-type/shared/input-styles.ts | 4 +- .../shared/data-type/shared/item-label.tsx | 6 +- .../shared/use-inherited-constraints.tsx | 17 +- .../src/pages/shared/data-types-context.tsx | 20 +- .../shared/discard-draft-entity-button.tsx | 56 +- .../src/pages/shared/entities-visualizer.tsx | 104 +- .../entities-visualizer/entities-table.tsx | 425 ++--- .../entities-table-value-cell.ts | 17 +- .../entities-table-value-cell/popup.tsx | 13 +- .../grid-view/grid-view-item-skeleton.tsx | 6 +- .../grid-view/grid-view-item.tsx | 24 +- .../entities-table/text-icon-cell.ts | 5 +- .../generate-table-data-from-rows.ts | 40 +- .../pages/shared/entities-visualizer/types.ts | 29 +- .../use-entities-table-data.tsx | 15 +- .../use-entities-visualizer-data.tsx | 18 +- .../pages/shared/entity-graph-visualizer.tsx | 18 +- .../src/pages/shared/entity-selector.tsx | 79 +- .../convert-type-menu-item.tsx | 11 +- .../entity-type-page/definition-tab.tsx | 28 +- .../use-editor-ontology-functions.ts | 46 +- .../entity-type-page/edit-bar-type-editor.tsx | 27 +- .../shared/entity-type-page/entities-tab.tsx | 10 +- .../entity-type-description.tsx | 4 +- .../entity-type-page/entity-type-plural.tsx | 5 +- .../entity-type-page/entity-type-tabs.tsx | 33 +- .../entity-type-page/file-uploads-tab.tsx | 49 +- .../file-uploads-tab/action.tsx | 28 +- .../shared/entity-type-header.tsx | 33 +- .../upgrade-dependents-modal.tsx | 128 +- .../use-entity-type-dependents.ts | 45 +- .../use-entity-type-value.tsx | 30 +- .../src/pages/shared/entity-type-selector.tsx | 19 +- .../src/pages/shared/entity-type.tsx | 53 +- .../hash-frontend/src/pages/shared/entity.tsx | 103 +- .../shared/entity/draft-entity-banner.tsx | 8 +- .../src/pages/shared/entity/edit-bar.tsx | 6 +- .../shared/entity/entity-editor-container.tsx | 4 +- .../src/pages/shared/entity/entity-editor.tsx | 5 +- .../entity/entity-editor/claims-section.tsx | 19 +- .../entity-editor/entity-editor-context.tsx | 25 +- .../entity-editor/file-preview-section.tsx | 68 +- .../entity/entity-editor/history-section.tsx | 16 +- .../history-section/get-history-events.ts | 76 +- .../history-section/history-table.tsx | 42 +- .../history-table/provenance.tsx | 23 +- .../provenance/sources-slideover.tsx | 21 +- .../history-table/shared/event-detail.tsx | 26 +- .../entity/entity-editor/link-section.tsx | 3 +- .../entity/entity-editor/links-section.tsx | 20 +- .../incoming-links-table.tsx | 755 ++++---- .../links-section/outgoing-links-section.tsx | 53 +- .../outgoing-links-section/cells/link-cell.ts | 5 +- .../cells/linked-with-cell.ts | 21 +- .../linked-entity-list-editor.tsx | 130 +- .../linked-entity-selector.tsx | 25 +- .../linked-with-cell-editor.tsx | 35 +- .../outgoing-links-section/constants.ts | 6 +- .../readonly-outgoing-links-table.tsx | 791 ++++----- .../outgoing-links-section/types.ts | 7 +- .../use-create-get-cell-content.ts | 10 +- .../outgoing-links-section/use-rows.ts | 25 +- .../entity-editor/properties-section.tsx | 21 +- .../properties-section/property-table.tsx | 10 +- .../property-table/cells/change-type-cell.tsx | 17 +- .../cells/property-name-cell.tsx | 29 +- .../property-table/cells/value-cell.tsx | 26 +- .../cells/value-cell/array-editor.tsx | 50 +- .../array-editor/add-another-button.tsx | 8 +- .../value-cell/array-editor/draft-row.tsx | 5 +- .../value-cell/array-editor/row-action.tsx | 6 +- .../value-cell/array-editor/sortable-row.tsx | 58 +- .../cells/value-cell/editor-type-picker.tsx | 3 +- .../cells/value-cell/inputs/boolean-input.tsx | 11 +- .../cells/value-cell/inputs/json-input.tsx | 27 +- .../inputs/json-input/json-editor.tsx | 8 +- .../cells/value-cell/single-value-editor.tsx | 45 +- .../property-table/cells/value-cell/types.ts | 5 +- .../property-table/constants.ts | 6 +- .../property-table/flatten.ts | 17 +- .../get-tooltips-of-property-row.ts | 9 +- .../use-create-get-cell-content.ts | 23 +- .../use-create-on-cell-edited.ts | 11 +- .../property-table/use-rows.ts | 19 +- .../generate-property-row-recursively.ts | 18 +- .../get-expected-types-of-property-type.ts | 6 +- .../use-rows/use-property-rows-from-entity.ts | 66 +- .../entity/entity-editor/shared/types.ts | 5 +- .../entity/entity-editor/types-section.tsx | 70 +- .../entity-type-change-modal.tsx | 118 +- .../use-get-type-change-details.ts | 53 +- .../src/pages/shared/entity/entity-header.tsx | 70 +- .../get-entity-multi-type-dependencies.ts | 28 +- .../src/pages/shared/entity/query-editor.tsx | 20 +- .../shared/create-draft-entity-subgraph.ts | 16 +- .../entity/shared/entity-editor-tabs.tsx | 18 +- .../shared/links-section-empty-state.tsx | 6 +- .../shared/properties-section-empty-state.tsx | 7 +- .../use-apply-draft-link-entity-changes.ts | 41 +- .../entity/shared/use-draft-link-state.ts | 6 +- .../entity/shared/use-handle-type-changes.ts | 37 +- .../shared/use-mark-link-entity-to-archive.ts | 3 +- .../pages/shared/flow-definitions-context.tsx | 7 +- .../src/pages/shared/flow-runs-context.tsx | 51 +- .../src/pages/shared/flow-tables.tsx | 22 +- .../pages/shared/format-kratos-message.tsx | 17 +- .../src/pages/shared/format-value.ts | 18 +- .../src/pages/shared/get-file-properties.ts | 5 +- .../src/pages/shared/graph-visualizer.tsx | 14 +- .../graph-visualizer/graph-container.tsx | 18 +- .../graph-container/graph-data-loader.tsx | 98 +- .../graph-container/path-finder-control.tsx | 151 +- .../path-finder-control/types.ts | 6 +- .../path-finder-control/worker.ts | 15 +- .../graph-container/search-control.tsx | 21 +- .../graph-container/shared/config-control.tsx | 97 +- .../shared/control-components.tsx | 21 +- .../graph-container/shared/filter-control.tsx | 35 +- .../filter-control/node-type-filters.tsx | 20 +- .../shared/full-screen-context.tsx | 9 +- .../graph-container/shared/graph-context.tsx | 49 +- .../shared/graph-viz-tooltip.tsx | 5 +- .../shared/simple-autocomplete.tsx | 26 +- .../shared/use-event-handlers.ts | 22 +- .../shared/use-set-draw-settings.ts | 60 +- .../pages/shared/gray-to-blue-icon-button.tsx | 4 +- .../src/pages/shared/inline-select.tsx | 4 +- .../google/google-account-select.tsx | 22 +- .../google/google-auth-context.tsx | 50 +- .../use-google-accounts.ts | 48 +- .../google/google-file-picker.tsx | 12 +- .../google/select-or-name-google-sheet.tsx | 13 +- .../src/pages/shared/invite-header.tsx | 36 +- ...link-label-with-source-and-destination.tsx | 210 +-- .../src/pages/shared/markdown.tsx | 63 +- .../src/pages/shared/markdown/elements.tsx | 6 +- .../shared/markdown/elements/snippet.tsx | 6 +- .../src/pages/shared/not-found.tsx | 10 +- .../src/pages/shared/number-or-text-input.tsx | 21 +- .../src/pages/shared/ory-kratos.ts | 13 +- .../src/pages/shared/pdf-preview.tsx | 88 +- .../shared/pdf-preview/page-thumbnail.tsx | 12 +- .../pages/shared/pdf-preview/pdf-search.tsx | 108 +- .../src/pages/shared/readonly-grid-popup.tsx | 4 +- apps/hash-frontend/src/pages/shared/sentry.ts | 4 +- .../src/pages/shared/settings-layout.tsx | 16 +- .../settings-layout/settings-sidebar.tsx | 32 +- .../pages/shared/shared/edit-bar-contents.tsx | 20 +- .../shared/shared/type-editor-styling.tsx | 9 +- .../pages/shared/shared/use-new-type-owner.ts | 4 +- .../src/pages/shared/slide-stack.tsx | 12 +- .../src/pages/shared/slide-stack/context.tsx | 4 +- .../shared/slide-stack/data-type-slide.tsx | 5 +- .../shared/slide-stack/entity-type-slide.tsx | 5 +- .../src/pages/shared/slide-stack/types.ts | 10 +- .../src/pages/shared/sso-provider-buttons.tsx | 16 +- .../src/pages/shared/table-header-toggle.tsx | 15 +- .../src/pages/shared/top-context-bar.tsx | 24 +- .../top-context-bar/archived-item-banner.tsx | 22 +- .../context-bar-actions-dropdown.tsx | 6 +- .../top-context-bar/share-dropdown-menu.tsx | 15 +- .../edit-authorization-status-menu.tsx | 76 +- .../editable-authorization-relationship.tsx | 83 +- .../invite-account-form.tsx | 50 +- .../share-dropdown-menu/privacy-menu-item.tsx | 7 +- .../share-entity-section.tsx | 164 +- .../share-dropdown-menu/types.ts | 10 +- .../src/pages/shared/top-context-bar/util.ts | 5 +- .../pages/shared/type-graph-visualizer.tsx | 26 +- .../src/pages/shared/types-table.tsx | 96 +- .../src/pages/shared/url-input.tsx | 7 +- .../shared/use-create-block-collection.ts | 87 +- .../src/pages/shared/use-flow-runs-usage.ts | 103 +- .../src/pages/shared/use-flow-schedules.ts | 6 +- .../shared/use-generate-type-urls-for-user.ts | 4 +- .../use-get-closed-multi-entity-type.ts | 3 +- .../shared/use-kratos-flow-error-handler.ts | 14 +- .../src/pages/shared/use-validate-entity.ts | 30 +- .../src/pages/shared/verify-email-step.tsx | 43 +- .../src/pages/shared/virtualized-table.tsx | 50 +- .../pages/shared/virtualized-table/header.tsx | 23 +- .../virtualized-table/header/filter.tsx | 53 +- .../shared/virtualized-table/header/sort.tsx | 15 +- .../virtualized-table/use-filter-state.tsx | 4 +- .../src/pages/shared/visualizer-views.tsx | 5 +- .../src/pages/shared/web-selector.tsx | 52 +- .../src/pages/shared/workspace-context.tsx | 50 +- apps/hash-frontend/src/pages/signin.page.tsx | 113 +- apps/hash-frontend/src/pages/signup.page.tsx | 22 +- .../signup.page/accept-org-invitation.tsx | 3 +- .../pages/signup.page/account-setup-form.tsx | 17 +- .../src/pages/signup.page/account-usage.tsx | 15 +- .../signup.page/signup-registration-form.tsx | 32 +- .../src/pages/signup.page/signup-steps.tsx | 19 +- .../src/pages/types/[[...type-kind]].page.tsx | 37 +- .../[[...type-kind]].page/types-page-tabs.tsx | 8 +- .../src/pages/verification.page.tsx | 49 +- .../src/pages/workers.page/flow-run-table.tsx | 366 ++-- .../workers.page/flow-schedules-table.tsx | 92 +- apps/hash-frontend/src/shared/command-bar.tsx | 76 +- .../src/shared/command-bar/cheat-sheet.tsx | 19 +- .../shared/command-bar/command-bar-options.ts | 19 +- .../src/shared/command-bar/hot-key.tsx | 22 +- .../shared/draft-entities-count-context.tsx | 57 +- .../src/shared/edit-emoji-icon-button.tsx | 15 +- .../emoji-picker/emoji-picker.tsx | 12 +- .../src/shared/entity-types-context/hooks.ts | 30 +- .../shared/entity-types-context/provider.tsx | 6 +- .../use-entity-types-context-value.ts | 38 +- .../shared/context-types.ts | 14 +- .../entity-types-context/shared/context.ts | 4 +- .../shared/is-special-entity-type.ts | 25 +- .../src/shared/file-upload-context.tsx | 129 +- apps/hash-frontend/src/shared/filters.tsx | 8 +- apps/hash-frontend/src/shared/frozen.tsx | 5 +- .../src/shared/generate-link-parameters.ts | 12 +- .../src/shared/get-block-dom-id.ts | 3 +- .../icons/arrow-down-a-z-regular-icon.tsx | 4 +- .../arrow-down-arrow-up-regular-icon.tsx | 4 +- .../arrow-right-to-bracket-regular-icon.tsx | 4 +- .../shared/icons/arrow-right-to-line-icon.tsx | 4 +- .../arrow-turn-down-left-regular-icon.tsx | 4 +- .../icons/arrow-up-a-z-regular-icon.tsx | 4 +- .../icons/arrow-up-right-regular-icon.tsx | 4 +- .../icons/arrows-from-line-regular-icon.tsx | 4 +- .../icons/arrows-to-line-regular-icon.tsx | 4 +- .../src/shared/icons/bold-icon.tsx | 8 +- .../shared/icons/calendar-day-light-icon.tsx | 4 +- .../icons/calendar-day-regular-icon.tsx | 4 +- .../shared/icons/calendar-days-light-icon.tsx | 4 +- .../shared/icons/calendar-week-light-icon.tsx | 4 +- .../icons/chart-network-regular-icon.tsx | 4 +- .../icons/chevron-down-regular-icon.tsx | 4 +- .../icons/chevron-left-regular-icon.tsx | 4 +- .../icons/chevron-right-regular-icon.tsx | 4 +- .../shared/icons/chevron-up-regular-icon.tsx | 4 +- .../icons/circle-arrow-right-regular-icon.tsx | 4 +- .../src/shared/icons/circle-info-icon.tsx | 8 +- .../shared/icons/circle-info-regular-icon.tsx | 4 +- .../shared/icons/earth-americas-regular.tsx | 12 +- .../icons/file-circle-plus-regular-icon.tsx | 4 +- .../shared/icons/file-export-regular-icon.tsx | 4 +- .../shared/icons/file-lines-regular-icon.tsx | 4 +- .../icons/file-powerpoint-light-icon.tsx | 4 +- .../src/shared/icons/gitlab-icon.tsx | 10 +- .../icons/grip-dots-vertical-regular-icon.tsx | 4 +- .../src/shared/icons/hash-lockup.tsx | 29 +- .../src/shared/icons/hightlighter-icon.tsx | 8 +- .../src/shared/icons/home-icon.tsx | 8 +- .../src/shared/icons/house-regular-icon.tsx | 8 +- .../src/shared/icons/house-solid-icon.tsx | 8 +- .../src/shared/icons/infinity-solid-icon.tsx | 8 +- .../src/shared/icons/italic-icon.tsx | 8 +- .../shared/icons/layer-group-light-icon.tsx | 8 +- .../shared/icons/magnifying-glass-light.tsx | 4 +- .../icons/magnifying-glass-regular-icon.tsx | 4 +- .../shared/icons/note-sticky-regular-icon.tsx | 4 +- .../src/shared/icons/pencil-slash-icon.tsx | 8 +- .../icons/person-booth-regular-icon.tsx | 4 +- .../src/shared/icons/plug-solid-icon.tsx | 8 +- .../src/shared/icons/strikethrough-icon.tsx | 8 +- .../triangle-exclamation-regular-icon.tsx | 4 +- .../src/shared/icons/underline-icon.tsx | 8 +- .../src/shared/icons/upload-icon.tsx | 8 +- .../src/shared/icons/upload-regular-icon.tsx | 8 +- .../src/shared/icons/user-icon.tsx | 8 +- .../src/shared/invites-context.tsx | 24 +- apps/hash-frontend/src/shared/is-archived.ts | 15 +- .../src/shared/is-href-external.ts | 4 +- apps/hash-frontend/src/shared/is-of-type.ts | 27 +- .../src/shared/keyboard-shortcuts-context.tsx | 85 +- .../use-property-types-context-value.ts | 17 +- apps/hash-frontend/src/shared/layout.tsx | 13 +- .../layout-with-header/account-dropdown.tsx | 35 +- .../layout-with-header/actions-dropdown.tsx | 27 +- .../notifications-dropdown.tsx | 7 +- .../layout/layout-with-header/page-header.tsx | 6 +- .../layout/layout-with-header/search-bar.tsx | 31 +- .../search-bar/search-input.tsx | 6 +- .../shared/header-icon-button-with-count.tsx | 11 +- .../shared/header-icon-button.tsx | 6 +- .../src/shared/layout/layout-with-sidebar.tsx | 20 +- .../layout-with-sidebar/sidebar-context.tsx | 4 +- .../layout/layout-with-sidebar/sidebar.tsx | 26 +- .../sidebar/account-entities-list.tsx | 25 +- .../sidebar/account-entity-type-list.tsx | 31 +- .../account-entity-type-list/search-input.tsx | 13 +- .../sidebar/account-page-list.tsx | 74 +- .../sidebar/account-page-list/page-menu.tsx | 4 +- .../account-page-list/page-tree-item.tsx | 6 +- .../sidebar/account-page-list/utils.ts | 32 +- .../sidebar/favorites-list.tsx | 18 +- .../shared/entity-or-type-sidebar-item.tsx | 18 +- .../entity-menu.tsx | 12 +- .../entity-type-menu.tsx | 5 +- .../shared/favorite-menu-item.tsx | 11 +- .../shared/sidebar-menu-item.tsx | 9 +- .../sidebar/shared/nav-link.tsx | 6 +- .../sidebar/shared/sort-actions-dropdown.tsx | 17 +- .../sidebar/shared/view-all-link.tsx | 3 +- .../sidebar/top-nav-link.tsx | 8 +- .../sidebar/workspace-switcher.tsx | 56 +- .../src/shared/notification-count-context.tsx | 129 +- .../src/shared/page-icon-button.tsx | 5 +- .../src/shared/property-types-context.tsx | 41 +- .../src/shared/readonly-mode.tsx | 3 +- .../src/shared/routing/route-page-info.tsx | 11 +- .../hash-frontend/src/shared/table-content.ts | 4 +- .../hash-frontend/src/shared/table-header.tsx | 36 +- .../table-header/bulk-actions-dropdown.tsx | 50 +- apps/hash-frontend/src/shared/ui/link.tsx | 51 +- apps/hash-frontend/src/shared/ui/modal.tsx | 6 +- apps/hash-frontend/src/shared/ui/tab-link.tsx | 4 +- apps/hash-frontend/src/shared/use-actors.ts | 31 +- .../src/shared/use-entity-icon.tsx | 14 +- .../src/shared/use-entity-type-entities.tsx | 35 +- .../src/shared/use-scroll-lock.ts | 8 +- .../src/shared/use-update-page-icon.ts | 5 +- .../src/shared/use-user-or-org.ts | 84 +- .../shared/use-user-permissions-on-entity.ts | 4 +- .../src/shared/workers-header.tsx | 10 +- apps/hash-graph/docs/structural-queries.md | 20 +- .../src/activities/flow-activities.ts | 8 +- .../flow-activities/aviation-activities.ts | 6 +- .../get-historical-flight-arrivals-action.ts | 37 +- .../get-live-flight-positions-action.ts | 106 +- .../get-scheduled-flights-action.ts | 24 +- .../flow-activities/integration-activities.ts | 6 +- .../persist-integration-entities-action.ts | 193 +- .../shared/split-properties-and-metadata.ts | 37 +- .../src/activities/linear-activities.ts | 105 +- .../activities/linear-activities/mappings.ts | 27 +- .../src/shared/graph-requests.ts | 71 +- apps/hash-integration-worker/src/workflows.ts | 34 +- .../src/workflows/run-flow-workflow.ts | 13 +- apps/mcp/linear/src/main.ts | 20 +- apps/mcp/notion/src/main.ts | 9 +- apps/mcp/notion/src/main/notion-services.ts | 5 +- apps/petrinaut-website/.oxlintrc.json | 33 +- apps/petrinaut-website/src/main/app.tsx | 36 +- .../src/main/app/use-local-storage-sdcpns.ts | 11 +- .../sentry/sentry-error-tracker-provider.tsx | 4 +- apps/petrinaut-website/vite.config.ts | 3 +- apps/plugin-browser/codegen.config.ts | 3 +- apps/plugin-browser/eslint.config.js | 3 +- .../src/graphql/queries/entity.queries.ts | 6 +- .../src/pages/options/options-contents.tsx | 14 +- .../src/pages/popup/popup-contents.tsx | 24 +- .../popup/popup-contents/action-center.tsx | 56 +- .../action-center/automated.tsx | 27 +- .../action-center/automated/select-scope.tsx | 10 +- .../select-scope/circle-exclamation-icon.tsx | 4 +- .../select-scope/rows-by-location.tsx | 74 +- .../automated/select-scope/rows-by-type.tsx | 39 +- .../automated/select-scope/select-domains.tsx | 15 +- .../select-scope/select-grouping.tsx | 18 +- .../select-scope/shared/common-rows-props.ts | 4 +- .../action-center/default-production-rules.ts | 218 ++- .../popup-contents/action-center/history.tsx | 20 +- .../history/automatically-triggered.tsx | 11 +- .../history/manually-triggered.tsx | 7 +- .../history/shared/event-table.tsx | 9 +- .../history/shared/history-row.tsx | 23 +- .../history-row/cell-with-hover-button.tsx | 3 +- .../history/shared/history-row/chip.tsx | 5 +- .../flow-metadata-cell-contents.tsx | 73 +- .../shared/history-row/flow-status-cell.tsx | 23 +- .../popup-contents/action-center/one-off.tsx | 5 +- .../one-off/infer-entities-action.tsx | 26 +- .../create-entity-icon.tsx | 8 +- .../one-off/quick-note-action.tsx | 42 +- .../action-center/shared/autocomplete-sx.ts | 12 +- .../shared/entity-type-selector.tsx | 58 +- .../action-center/shared/model-selector.tsx | 16 +- .../shared/model-selector/openai-icon.tsx | 5 +- .../action-center/shared/section.tsx | 13 +- .../shared/select-web-target/web-selector.tsx | 26 +- .../action-center/shared/tab-props.ts | 8 +- .../action-center/shared/use-flow-runs.ts | 25 +- .../popup/popup-contents/not-enabled.tsx | 18 +- .../popup-contents/shared/user-context.tsx | 10 +- .../pages/popup/popup-contents/sign-in.tsx | 15 +- .../sign-in/hash-rainbow-lockup.tsx | 8 +- .../src/pages/shared/use-entity-types.ts | 26 +- .../src/pages/shared/use-storage-sync.ts | 5 +- .../src/pages/working/working-contents.tsx | 13 +- apps/plugin-browser/src/scripts/background.ts | 73 +- .../src/scripts/background/infer-entities.ts | 35 +- .../infer-entities/get-website-content.ts | 17 +- apps/plugin-browser/src/scripts/content.ts | 8 +- .../src/shared/create-default-settings.ts | 31 +- .../src/shared/create-entity.ts | 23 +- apps/plugin-browser/src/shared/get-user.ts | 74 +- apps/plugin-browser/src/shared/messages.ts | 5 +- .../src/shared/query-graphql-api.ts | 5 +- apps/plugin-browser/src/shared/storage.ts | 60 +- .../src/shared/storage/update-entity.ts | 25 +- apps/plugin-browser/utils/build.js | 4 +- apps/plugin-browser/utils/webserver.js | 4 +- apps/plugin-browser/webpack.config.js | 25 +- libs/@blockprotocol/graph/README.md | 5 +- libs/@blockprotocol/graph/eslint.config.js | 3 +- .../graph/scripts/prepublish.ts | 5 +- libs/@blockprotocol/graph/src/codegen.ts | 5 +- .../compile/compile-schemas-to-typescript.ts | 16 +- .../compile/remove-placeholder-types.ts | 9 +- .../compile/replace-interface-with-type.ts | 8 +- .../graph/src/codegen/context/compile.ts | 26 +- .../graph/src/codegen/context/initialize.ts | 18 +- .../graph/src/codegen/context/postprocess.ts | 32 +- .../graph/src/codegen/context/preprocess.ts | 18 +- .../graph/src/codegen/context/shared.ts | 8 +- .../codegen/initialize/clean-output-dir.ts | 4 +- .../initialize/ensure-output-dir-exists.ts | 8 +- .../metadata/generate-metadata-schema.ts | 25 +- .../traverse-and-collate-schemas.ts | 47 +- .../src/codegen/initialize/traverse/fetch.ts | 5 +- .../initialize/traverse/type-validation.ts | 11 +- .../graph/src/codegen/parameters.ts | 60 +- .../add-metadata-dependencies-to-files.ts | 4 +- .../postprocess/allocate-types-to-files.ts | 29 +- ...identifier-definitions-to-file-contents.ts | 12 +- .../generate-block-entity-type-aliases.ts | 12 +- .../generate-block-link-target-aliases.ts | 13 +- .../generate-entity-definitions.ts | 25 +- .../generate-link-and-target-definitions.ts | 86 +- .../postprocess/prepend-banner-comments.ts | 3 +- .../prepend-imports-and-exports.ts | 28 +- .../src/codegen/postprocess/write-to-files.ts | 4 +- .../preprocess/identify-link-entity-types.ts | 10 +- .../remove-redundant-data-type-inheritance.ts | 12 +- .../preprocess/transform-type-titles.ts | 39 +- .../graph/src/codegen/shared.ts | 8 +- .../graph/src/custom-element.ts | 12 +- .../graph/src/graph-block-handler.ts | 25 +- .../graph/src/graph-embedder-handler.ts | 5 +- .../graph/src/graph-module.json | 46 +- .../src/internal/mutate-subgraph/edge.ts | 209 +-- .../src/internal/mutate-subgraph/element.ts | 18 +- libs/@blockprotocol/graph/src/react.ts | 24 +- libs/@blockprotocol/graph/src/stdlib/bound.ts | 30 +- .../graph/src/stdlib/interval.ts | 38 +- .../graph/src/stdlib/subgraph/builder.ts | 15 +- .../src/stdlib/subgraph/edge/entity-type.ts | 16 +- .../src/stdlib/subgraph/edge/link-entity.ts | 157 +- .../src/stdlib/subgraph/edge/property-type.ts | 16 +- .../graph/src/stdlib/subgraph/edge/shared.ts | 18 +- .../src/stdlib/subgraph/element/data-type.ts | 21 +- .../stdlib/subgraph/element/entity-type.ts | 45 +- .../src/stdlib/subgraph/element/entity.ts | 46 +- .../stdlib/subgraph/element/map-revisions.ts | 23 +- .../stdlib/subgraph/element/property-type.ts | 51 +- .../graph/src/stdlib/subgraph/roots.ts | 31 +- .../src/stdlib/subgraph/temporal-axes.ts | 5 +- .../stdlib/subgraph/vertex-id-for-element.ts | 11 +- .../graph/src/types/block-graph.ts | 24 +- libs/@blockprotocol/graph/src/types/entity.ts | 19 +- libs/@blockprotocol/graph/src/types/file.ts | 14 +- .../graph/src/types/ontology.ts | 4 +- .../graph/src/types/ontology/data-type.ts | 6 +- .../graph/src/types/ontology/property-type.ts | 15 +- .../graph/src/types/subgraph.ts | 6 +- .../graph/src/types/subgraph/edges.ts | 5 +- .../subgraph/edges/generic-outward-edge.ts | 9 +- .../graph/src/types/subgraph/edges/kind.ts | 9 +- .../src/types/subgraph/edges/outward-edge.ts | 10 +- .../subgraph/edges/variants/knowledge.ts | 16 +- .../types/subgraph/edges/variants/ontology.ts | 30 +- .../src/types/subgraph/element-mappings.ts | 18 +- .../graph/src/types/subgraph/vertices.ts | 24 +- .../util/string-is-non-negative-integer.ts | 4 +- libs/@blockprotocol/graph/src/util/subtype.ts | 5 +- .../graph/src/util/typed-entries.ts | 13 +- .../type-system/typescript/eslint.config.js | 3 +- .../typescript/scripts/prepublish.ts | 43 +- .../typescript/src/native/entity-type.ts | 16 +- .../typescript/src/native/entity.ts | 41 +- .../src/native/ontology-metadata.ts | 13 +- .../typescript/src/native/property-type.ts | 13 +- .../type-system/typescript/src/native/url.ts | 55 +- .../type-system/typescript/test/url.test.ts | 92 +- .../block-design-system/eslint.config.js | 10 +- .../src/ai-assistant-message.tsx | 20 +- .../src/ai-assistant-message/code-block.tsx | 28 +- .../src/block-error-message.tsx | 8 +- .../src/block-prompt-input.tsx | 59 +- .../src/block-settings-button.tsx | 8 +- .../src/dropdown-selector.tsx | 5 +- .../src/editable-field.tsx | 23 +- .../src/entities-graph-chart.tsx | 57 +- .../block-design-system/src/get-help-link.tsx | 9 +- .../src/icons/chevron-right.tsx | 8 +- .../src/icons/circle-question.tsx | 8 +- .../src/icons/code-pen.tsx | 8 +- .../block-design-system/src/icons/copy.tsx | 8 +- .../block-design-system/src/icons/gear.tsx | 8 +- .../src/icons/pen-to-square.tsx | 8 +- .../block-design-system/src/icons/pen.tsx | 8 +- .../@hashintel/design-system/eslint.config.js | 10 +- .../design-system/src/alert-modal.tsx | 9 +- .../design-system/src/autocomplete.tsx | 20 +- libs/@hashintel/design-system/src/avatar.tsx | 3 +- libs/@hashintel/design-system/src/button.tsx | 6 +- libs/@hashintel/design-system/src/callout.tsx | 23 +- .../design-system/src/chip-group.tsx | 62 +- libs/@hashintel/design-system/src/chip.tsx | 13 +- .../design-system/src/data-type-selector.tsx | 46 +- libs/@hashintel/design-system/src/e-chart.tsx | 15 +- .../design-system/src/entity-or-type-icon.tsx | 31 +- .../design-system/src/fontawesome-icon.tsx | 88 +- .../design-system/src/form-inline.tsx | 4 +- .../src/icon-angle-right-regular.tsx | 4 +- ...down-left-and-arrow-up-right-to-center.tsx | 7 +- .../src/icon-arrow-down-regular.tsx | 12 +- .../design-system/src/icon-arrow-left.tsx | 8 +- .../src/icon-arrow-right-regular.tsx | 12 +- .../src/icon-arrow-rotate-left.tsx | 8 +- .../src/icon-arrow-up-regular.tsx | 8 +- ...-right-and-arrow-down-left-from-center.tsx | 7 +- ...con-arrow-up-right-from-square-regular.tsx | 12 +- .../src/icon-arrow-up-right-regular.tsx | 12 +- .../design-system/src/icon-arrow-up-right.tsx | 8 +- .../src/icon-arrow-up-wide-short-light.tsx | 12 +- .../src/icon-arrows-rotate-regular.tsx | 12 +- .../design-system/src/icon-at-regular.tsx | 8 +- .../design-system/src/icon-barcode.tsx | 5 +- .../design-system/src/icon-bell-light.tsx | 5 +- .../@hashintel/design-system/src/icon-bug.tsx | 5 +- .../design-system/src/icon-bullseye-light.tsx | 8 +- .../design-system/src/icon-check-regular.tsx | 8 +- .../design-system/src/icon-check.tsx | 8 +- .../design-system/src/icon-chrome.tsx | 17 +- .../src/icon-circle-check-regular.tsx | 12 +- .../src/icon-circle-ellipsis-regular.tsx | 12 +- .../src/icon-circle-nodes-light.tsx | 12 +- .../src/icon-circle-one-regular.tsx | 12 +- .../design-system/src/icon-clock-regular.tsx | 8 +- .../design-system/src/icon-close.tsx | 5 +- .../design-system/src/icon-code.tsx | 8 +- .../design-system/src/icon-copy-regular.tsx | 8 +- .../design-system/src/icon-dash.tsx | 8 +- .../src/icon-diagram-nested-light.tsx | 5 +- .../src/icon-diagram-regular.tsx | 5 +- .../src/icon-download-regular.tsx | 5 +- .../design-system/src/icon-eye-regular.tsx | 5 +- .../src/icon-eye-slash-regular.tsx | 5 +- .../design-system/src/icon-eye-solid.tsx | 5 +- .../design-system/src/icon-file-regular.tsx | 5 +- .../src/icon-file-spreadsheet-regular.tsx | 12 +- .../src/icon-file-spreadsheet-solid.tsx | 12 +- .../src/icon-forward-step-solid.tsx | 12 +- .../design-system/src/icon-graph.tsx | 5 +- .../design-system/src/icon-image-regular.tsx | 8 +- .../design-system/src/icon-image-solid.tsx | 8 +- .../src/icon-input-pipe-regular.tsx | 4 +- .../src/icon-lightbulb-on-rainbow.tsx | 4 +- .../src/icon-lightbulb-on-regular.tsx | 12 +- .../src/icon-magnifying-glass-minus-light.tsx | 4 +- .../src/icon-magnifying-glass-plus-light.tsx | 4 +- .../src/icon-magnifying-glass-regular.tsx | 4 +- .../src/icon-memo-circle-check-regular.tsx | 12 +- .../src/icon-microscope-regular.tsx | 12 +- .../src/icon-pen-to-square-solid.tsx | 12 +- .../src/icon-person-running-regular.tsx | 4 +- .../design-system/src/icon-play-solid.tsx | 8 +- .../design-system/src/icon-rotate-regular.tsx | 5 +- .../design-system/src/icon-ruler-regular.tsx | 8 +- .../design-system/src/icon-shapes-regular.tsx | 8 +- .../src/icon-sidebar-regular.tsx | 8 +- .../design-system/src/icon-sparkles-light.tsx | 8 +- .../design-system/src/icon-stop-solid.tsx | 8 +- .../design-system/src/icon-table-light.tsx | 8 +- .../design-system/src/icon-terminal-light.tsx | 8 +- .../src/icon-thought-bubble-light.tsx | 12 +- .../src/icon-wand-magic-sparkles.tsx | 5 +- .../design-system/src/input-props.tsx | 25 +- .../design-system/src/menu-checkbox-item.tsx | 8 +- .../design-system/src/menu-item.tsx | 34 +- libs/@hashintel/design-system/src/modal.tsx | 6 +- .../design-system/src/ontology-chip.tsx | 33 +- .../design-system/src/ontology-icons.tsx | 40 +- libs/@hashintel/design-system/src/palettes.ts | 8 +- .../src/parse-url-for-ontology-chip.tsx | 7 +- .../src/popper-placement-modifier.ts | 4 +- libs/@hashintel/design-system/src/select.tsx | 21 +- .../src/selector-autocomplete.tsx | 31 +- .../selector-autocomplete-option.tsx | 33 +- .../@hashintel/design-system/src/skeleton.tsx | 8 +- .../src/submit-button-wrapper.tsx | 19 +- libs/@hashintel/design-system/src/theme.ts | 3 +- .../data-display/mui-chip-theme-options.tsx | 13 +- .../mui-list-item-button-theme-options.ts | 115 +- .../mui-list-item-icon-theme-options.ts | 25 +- .../mui-list-item-text-theme-options.ts | 19 +- .../inputs/mui-button-theme-options.ts | 13 +- .../checkbox-blank-icon.tsx | 5 +- .../mui-form-helper-text-theme-options.ts | 33 +- .../mui-outlined-input-theme-options.ts | 189 +- .../radio-checked-icon.tsx | 5 +- .../radio-unchecked-icon.tsx | 5 +- .../navigation/mui-menu-item-theme-options.ts | 59 +- .../utils/mui-css-baseline-theme-options.ts | 5 +- .../design-system/src/type-card.tsx | 9 +- .../design-system/src/white-card.tsx | 14 +- .../ds-components/.ladle/components.tsx | 5 +- .../.ladle/components/preview-frame.tsx | 6 +- .../.ladle/components/variant-grid.tsx | 6 +- .../.ladle/hooks/use-ladle-control.ts | 9 +- .../@hashintel/ds-components/.ladle/index.css | 25 +- .../@hashintel/ds-components/eslint.config.js | 6 +- .../ds-components/panda.local.config.ts | 6 +- .../ds-components/playwright.config.ts | 5 +- .../ds-components/postcss.config.cjs | 4 +- .../scripts/generate-colors-radix.ts | 64 +- .../ds-components/scripts/generate-tokens.ts | 4 +- .../migrate-beta-fractal-pilots.test.ts | 45 +- .../scripts/migrate-beta-fractal-pilots.ts | 115 +- .../ds-components/scripts/transforms.test.ts | 8 +- .../ds-components/scripts/transforms.ts | 4 +- .../src/beta/accordion.recipe.ts | 4 +- .../ds-components/src/beta/accordion.tsx | 10 +- .../src/beta/alert/closable.story.tsx | 8 +- .../ds-components/src/beta/avatar.tsx | 25 +- .../src/beta/avatar/badge.story.tsx | 7 +- .../src/beta/avatar/closed.story.tsx | 7 +- .../src/beta/avatar/colors.story.tsx | 9 +- .../src/beta/avatar/group.story.tsx | 7 +- .../src/beta/breadcrumb.recipe.ts | 4 +- .../src/beta/breadcrumb/closed.story.tsx | 56 +- .../ds-components/src/beta/button.tsx | 94 +- .../src/beta/card/avatar.story.tsx | 3 +- .../src/beta/card/form.story.tsx | 3 +- .../src/beta/card/horizontal.story.tsx | 3 +- .../src/beta/card/image.story.tsx | 3 +- .../ds-components/src/beta/carousel.recipe.ts | 4 +- .../ds-components/src/beta/carousel.tsx | 10 +- .../src/beta/carousel/auto-play.story.tsx | 6 +- .../src/beta/carousel/basic.story.tsx | 6 +- .../src/beta/carousel/multiple.story.tsx | 6 +- .../src/beta/carousel/scroll-to.story.tsx | 13 +- .../src/beta/carousel/vertical.story.tsx | 13 +- .../ds-components/src/beta/checkbox.recipe.ts | 4 +- .../ds-components/src/beta/checkbox.tsx | 48 +- .../src/beta/checkbox/closed.story.tsx | 36 +- .../src/beta/checkbox/controlled.story.tsx | 5 +- .../src/beta/checkbox/description.story.tsx | 4 +- .../src/beta/checkbox/indeterminate.story.tsx | 4 +- .../src/beta/clipboard.recipe.ts | 4 +- .../ds-components/src/beta/clipboard.tsx | 34 +- .../ds-components/src/beta/close-button.tsx | 22 +- .../src/beta/collapsible.recipe.ts | 4 +- .../src/beta/collapsible/basic.story.tsx | 5 +- .../src/beta/collapsible/lazy-mount.story.tsx | 5 +- .../collapsible/unmount-on-exit.story.tsx | 7 +- .../src/beta/color-picker.recipe.ts | 4 +- .../ds-components/src/beta/color-picker.tsx | 60 +- .../src/beta/color-picker/basic.story.tsx | 8 +- .../ds-components/src/beta/combobox.recipe.ts | 4 +- .../ds-components/src/beta/combobox.tsx | 42 +- .../src/beta/combobox/basic.story.tsx | 5 +- .../src/beta/date-picker.recipe.ts | 4 +- .../ds-components/src/beta/date-picker.tsx | 15 +- .../src/beta/date-picker/basic.story.tsx | 36 +- .../ds-components/src/beta/dialog.tsx | 28 +- .../src/beta/dialog/alert.story.tsx | 4 +- .../ds-components/src/beta/display-value.tsx | 8 +- .../display-value/with-formatting.story.tsx | 10 +- .../ds-components/src/beta/editable.recipe.ts | 4 +- .../ds-components/src/beta/editable.tsx | 10 +- .../src/beta/editable/controlled.story.tsx | 6 +- .../src/beta/editable/double-click.story.tsx | 5 +- .../ds-components/src/beta/field.tsx | 5 +- .../src/beta/field/closed.story.tsx | 7 +- .../ds-components/src/beta/fieldset.recipe.ts | 4 +- .../src/beta/fieldset/basic.story.tsx | 4 +- .../src/beta/fieldset/disabled.story.tsx | 4 +- .../src/beta/fieldset/invalid.story.tsx | 10 +- .../src/beta/file-upload.recipe.ts | 4 +- .../ds-components/src/beta/file-upload.tsx | 109 +- .../beta/file-upload/image-preview.story.tsx | 8 +- .../src/beta/heading/weights.story.tsx | 16 +- .../src/beta/hover-card.recipe.ts | 4 +- .../ds-components/src/beta/hover-card.tsx | 3 +- .../src/beta/hover-card/controlled.story.tsx | 4 +- .../src/beta/hover-card/dialog.story.tsx | 5 +- .../ds-components/src/beta/icon-button.tsx | 8 +- .../ds-components/src/beta/image.tsx | 9 +- .../src/beta/input-group.recipe.ts | 4 +- .../ds-components/src/beta/input-group.tsx | 40 +- .../src/beta/input-group/sizes.story.tsx | 7 +- .../src/beta/input-group/variants.story.tsx | 6 +- .../src/beta/input/field.story.tsx | 4 +- .../ds-components/src/beta/menu.tsx | 37 +- .../src/beta/menu/context.story.tsx | 4 +- .../src/beta/menu/radio-group.story.tsx | 5 +- .../src/beta/number-input.recipe.ts | 4 +- .../ds-components/src/beta/number-input.tsx | 20 +- .../src/beta/number-input/closed.story.tsx | 20 +- .../beta/number-input/helper-text.story.tsx | 4 +- .../src/beta/pagination.recipe.ts | 4 +- .../ds-components/src/beta/pagination.tsx | 6 +- .../src/beta/pin-input.recipe.ts | 4 +- .../src/beta/pin-input/closed.story.tsx | 32 +- .../src/beta/pin-input/field.story.tsx | 4 +- .../ds-components/src/beta/popover.recipe.ts | 4 +- .../src/beta/popover/dialog.story.tsx | 3 +- .../src/beta/popover/form.story.tsx | 4 +- .../src/beta/popover/initial-focus.story.tsx | 10 +- .../ds-components/src/beta/progress.recipe.ts | 4 +- .../src/beta/progress/closed.story.tsx | 28 +- .../src/beta/radio-card-group.recipe.ts | 4 +- .../src/beta/radio-card-group.tsx | 4 +- .../beta/radio-card-group/variants.story.tsx | 6 +- .../src/beta/radio-group.recipe.ts | 4 +- .../src/beta/radio-group/closed.story.tsx | 4 +- .../src/beta/radio-group/disabled.story.tsx | 6 +- .../src/beta/rating-group.recipe.ts | 4 +- .../ds-components/src/beta/rating-group.tsx | 41 +- .../src/beta/rating-group/closed.story.tsx | 26 +- .../src/beta/rating-group/colors.story.tsx | 7 +- .../beta/rating-group/controlled.story.tsx | 6 +- .../src/beta/scroll-area.recipe.ts | 7 +- .../scroll-area/infinite-scroll.story.tsx | 15 +- .../src/beta/segment-group.recipe.ts | 4 +- .../ds-components/src/beta/segment-group.tsx | 15 +- .../ds-components/src/beta/select.tsx | 41 +- .../ds-components/src/beta/skeleton.tsx | 34 +- .../ds-components/src/beta/slider.tsx | 5 +- .../ds-components/src/beta/splitter.recipe.ts | 4 +- .../ds-components/src/beta/splitter.tsx | 5 +- .../src/beta/splitter/store.story.tsx | 4 +- .../src/beta/splitter/vertical.story.tsx | 6 +- .../ds-components/src/beta/switch.tsx | 52 +- .../src/beta/switch/closed.story.tsx | 58 +- .../src/beta/switch/controlled.story.tsx | 5 +- .../src/beta/table/horizontal.story.tsx | 7 +- .../src/beta/table/sticky-column.story.tsx | 7 +- .../src/beta/tabs/lazy-mount.story.tsx | 6 +- .../src/beta/tags-input.recipe.ts | 4 +- .../ds-components/src/beta/tags-input.tsx | 25 +- .../src/beta/tags-input/sizes.story.tsx | 6 +- .../src/beta/tags-input/variants.story.tsx | 6 +- .../src/beta/text/line-clamp.story.tsx | 7 +- .../ds-components/src/beta/text/ref.story.tsx | 6 +- .../src/beta/text/truncate.story.tsx | 4 +- .../src/beta/textarea/field.story.tsx | 4 +- .../src/beta/textarea/sizes.story.tsx | 7 +- .../ds-components/src/beta/toast.tsx | 15 +- .../src/beta/toggle-group.recipe.ts | 4 +- .../src/beta/toggle-group/basic.story.tsx | 7 +- .../src/beta/toggle-group/toolbar.story.tsx | 7 +- .../ds-components/src/beta/tooltip.recipe.ts | 4 +- .../ds-components/src/beta/tooltip.tsx | 66 +- .../src/beta/tooltip/placement.story.tsx | 5 +- .../src/components/Avatar/avatar.stories.tsx | 22 +- .../src/components/Avatar/avatar.tsx | 9 +- .../src/components/Badge/badge.stories.tsx | 18 +- .../src/components/Badge/badge.tsx | 10 +- .../src/components/Button/button.recipe.ts | 11 +- .../src/components/Button/button.stories.tsx | 19 +- .../src/components/Button/button.tsx | 88 +- .../components/Checkbox/checkbox.stories.tsx | 10 +- .../src/components/Checkbox/checkbox.tsx | 16 +- .../src/components/Icon/icon.stories.tsx | 11 +- .../NumberInput/number-input.stories.tsx | 52 +- .../components/NumberInput/number-input.tsx | 27 +- .../RadioGroup/radio-group.stories.tsx | 26 +- .../src/components/RadioGroup/radio-group.tsx | 24 +- .../segmented-control.stories.tsx | 9 +- .../SegmentedControl/segmented-control.tsx | 9 +- .../src/components/Slider/slider.stories.tsx | 3 +- .../src/components/Slider/slider.tsx | 3 +- .../src/components/Switch/switch.tsx | 6 +- .../components/TextInput/base-input.recipe.ts | 32 +- .../src/components/TextInput/base-input.tsx | 47 +- .../TextInput/text-input.stories.tsx | 31 +- .../src/components/TextInput/text-input.tsx | 4 +- .../components/Tooltip/tooltip.stories.tsx | 10 +- .../src/components/Tooltip/tooltip.tsx | 13 +- libs/@hashintel/ds-components/src/main.ts | 5 +- libs/@hashintel/ds-components/src/preset.ts | 15 +- .../ds-components/src/preset/document.ts | 3 +- .../src/preset/stories/_types.ts | 10 +- .../stories/tokens.color-layering.story.tsx | 27 +- .../stories/tokens.color-migration.story.tsx | 18 +- .../stories/tokens.color-palettes.story.tsx | 61 +- .../stories/tokens.color-variants.story.tsx | 54 +- .../src/preset/stories/tokens.radii.story.tsx | 23 +- .../preset/stories/tokens.shadows.story.tsx | 80 +- .../preset/stories/tokens.spacing.story.tsx | 10 +- .../stories/tokens.typography.story.tsx | 43 +- .../ds-components/src/preset/tokens.ts | 20 +- .../ds-components/src/preset/tokens/gen.ts | 7 +- .../src/preset/tokens/stubs/shadows.ts | 36 +- .../ds-components/src/preset/tokens/utils.ts | 5 +- .../ds-components/src/util/form-shared.ts | 8 +- .../ds-components/tests/build-info.test.ts | 7 +- libs/@hashintel/ds-components/tsup.config.ts | 7 +- libs/@hashintel/petrinaut-core/.oxlintrc.json | 14 +- .../petrinaut-core/src/action-schemas.ts | 79 +- .../petrinaut-core/src/actions.test.ts | 8 +- libs/@hashintel/petrinaut-core/src/actions.ts | 40 +- libs/@hashintel/petrinaut-core/src/ai.ts | 14 +- .../src/clipboard/deduplicate-name.test.ts | 21 +- .../src/clipboard/deduplicate-name.ts | 5 +- .../src/clipboard/paste.test.ts | 28 +- .../petrinaut-core/src/clipboard/paste.ts | 29 +- .../src/clipboard/serialize.test.ts | 40 +- .../petrinaut-core/src/clipboard/serialize.ts | 18 +- .../petrinaut-core/src/default-codes.ts | 9 +- .../petrinaut-core/src/environment.ts | 36 +- libs/@hashintel/petrinaut-core/src/errors.ts | 5 +- .../src/examples/broken-machines.ts | 788 +++++---- .../src/examples/deployment-pipeline.ts | 7 +- .../src/examples/satellites-launcher.ts | 24 +- .../petrinaut-core/src/examples/sir-model.ts | 12 +- .../src/file-format/parse-sdcpn-file.ts | 12 +- .../src/file-format/remove-visual-info.ts | 13 +- .../src/file-format/sdcpn-to-tikz.ts | 17 +- libs/@hashintel/petrinaut-core/src/handle.ts | 24 +- libs/@hashintel/petrinaut-core/src/index.ts | 28 +- .../@hashintel/petrinaut-core/src/instance.ts | 21 +- .../petrinaut-core/src/lib/deep-equal.ts | 5 +- .../petrinaut-core/src/lib/typed-entries.ts | 9 +- .../petrinaut-core/src/lsp/index.ts | 6 +- .../petrinaut-core/src/lsp/language-client.ts | 34 +- .../src/lsp/lib/checker.test.ts | 20 +- .../petrinaut-core/src/lsp/lib/checker.ts | 32 +- .../lib/create-sdcpn-language-service.test.ts | 95 +- .../lsp/lib/create-sdcpn-language-service.ts | 48 +- .../src/lsp/lib/document-uris.test.ts | 66 +- .../src/lsp/lib/document-uris.ts | 32 +- .../petrinaut-core/src/lsp/lib/file-paths.ts | 25 +- .../src/lsp/lib/generate-virtual-files.ts | 19 +- .../src/lsp/lib/ts-to-lsp.test.ts | 33 +- .../petrinaut-core/src/lsp/lib/ts-to-lsp.ts | 10 +- .../petrinaut-core/src/lsp/transport.ts | 4 +- .../worker/create-language-server-worker.ts | 8 +- .../src/lsp/worker/language-server.worker.ts | 85 +- .../petrinaut-core/src/parameter-values.ts | 4 +- .../petrinaut-core/src/playback/playback.ts | 15 +- .../src/schemas/entity-schemas.ts | 50 +- .../src/schemas/scenario-schema.ts | 13 +- .../petrinaut-core/src/simulation/README.md | 15 +- .../petrinaut-core/src/simulation/api.ts | 5 +- .../authoring/metric/compile-metric.ts | 15 +- .../src/simulation/authoring/sandbox.ts | 4 +- .../scenario/compile-scenario.test.ts | 92 +- .../authoring/scenario/compile-scenario.ts | 34 +- .../user-code/compile-user-code.test.ts | 22 +- .../authoring/user-code/compile-user-code.ts | 20 +- .../engine/build-simulation.test.ts | 9 +- .../src/simulation/engine/build-simulation.ts | 62 +- .../check-transition-enablement.test.ts | 105 +- .../engine/check-transition-enablement.ts | 20 +- .../engine/compute-next-frame.test.ts | 3 +- .../simulation/engine/compute-next-frame.ts | 48 +- .../engine/compute-place-next-state.test.ts | 12 +- .../engine/compute-place-next-state.ts | 10 +- .../compute-possible-transition.test.ts | 28 +- .../engine/compute-possible-transition.ts | 68 +- .../enumerate-weighted-markings.test.ts | 4 +- .../engine/enumerate-weighted-markings.ts | 12 +- .../engine/execute-transitions.test.ts | 69 +- .../simulation/engine/execute-transitions.ts | 36 +- ...emove-tokens-from-simulation-frame.test.ts | 62 +- .../remove-tokens-from-simulation-frame.ts | 19 +- .../simulation/engine/sample-distribution.ts | 5 +- .../src/simulation/engine/types.ts | 9 +- .../simulation/frames/frame-reader.test.ts | 10 +- .../src/simulation/frames/frame-reader.ts | 13 +- .../src/simulation/frames/internal-frame.ts | 112 +- .../src/simulation/monte-carlo/advance-run.ts | 16 +- .../simulation/monte-carlo/frame-buffer.ts | 69 +- .../monte-carlo/frame-operations.ts | 70 +- .../src/simulation/monte-carlo/layout.ts | 14 +- .../metrics/place-token-count-distribution.ts | 10 +- .../simulation/monte-carlo/metrics/types.ts | 9 +- .../monte-carlo/monte-carlo-simulator.test.ts | 45 +- .../monte-carlo/monte-carlo-simulator.ts | 26 +- .../src/simulation/monte-carlo/run-state.ts | 33 +- .../monte-carlo/runtime/experiment.test.ts | 18 +- .../monte-carlo/runtime/experiment.ts | 15 +- .../monte-carlo/transition-effect.ts | 33 +- .../src/simulation/monte-carlo/types.ts | 4 +- .../worker/create-monte-carlo-worker.ts | 3 +- .../monte-carlo/worker/monte-carlo.worker.ts | 16 +- .../src/simulation/runtime/simulation.test.ts | 15 +- .../src/simulation/runtime/simulation.ts | 4 +- .../src/simulation/runtime/transport.ts | 4 +- .../worker/simulation.worker.test.ts | 4 +- .../simulation/worker/simulation.worker.ts | 37 +- .../petrinaut-core/src/types/selection.ts | 4 +- .../src/validation/display-name.ts | 8 +- .../src/validation/entity-name.ts | 4 +- .../src/validation/variable-name.ts | 8 +- libs/@hashintel/petrinaut-core/vite.config.ts | 22 +- libs/@hashintel/petrinaut/.oxlintrc.json | 33 +- .../petrinaut/panda.config.shared.test.ts | 8 +- .../petrinaut/panda.config.shared.ts | 8 +- .../src/react/experiments/context.ts | 15 +- .../src/react/experiments/provider.test.tsx | 37 +- .../src/react/experiments/provider.tsx | 68 +- .../src/react/hooks/use-block-window-close.ts | 6 +- .../hooks/use-default-parameter-values.ts | 6 +- .../petrinaut/src/react/hooks/use-document.ts | 8 +- .../petrinaut/src/react/hooks/use-lsp.ts | 5 +- .../petrinaut/src/react/hooks/use-playback.ts | 11 +- .../src/react/hooks/use-simulation.ts | 5 +- libs/@hashintel/petrinaut/src/react/index.ts | 5 +- .../petrinaut/src/react/lsp/context.ts | 15 +- .../petrinaut/src/react/lsp/provider.tsx | 8 +- .../src/react/mutation-provider.test.tsx | 25 +- .../petrinaut/src/react/mutation-provider.tsx | 15 +- .../src/react/net-management-context.ts | 4 +- .../src/react/notifications/provider.tsx | 12 +- .../src/react/notifications/toaster.tsx | 6 +- .../src/react/petrinaut-provider.tsx | 23 +- .../petrinaut/src/react/playback/context.ts | 9 +- .../src/react/playback/provider.test.tsx | 31 +- .../petrinaut/src/react/playback/provider.tsx | 50 +- .../petrinaut/src/react/sdcpn-provider.tsx | 24 +- .../petrinaut/src/react/simulation/context.ts | 28 +- .../src/react/simulation/provider.tsx | 103 +- .../src/react/state/editor-context.ts | 13 +- .../src/react/state/editor-provider.tsx | 50 +- .../src/react/state/mutation-context.ts | 4 +- .../react/state/portal-container-context.tsx | 7 +- .../src/react/state/sdcpn-context.ts | 13 +- .../src/react/state/use-is-read-only.ts | 4 +- .../src/react/state/use-selection-cleanup.ts | 15 +- .../state/use-sync-editor-to-settings.ts | 6 +- .../src/react/state/user-settings-context.ts | 15 +- .../react/state/user-settings-provider.tsx | 40 +- .../react/use-handle-history-as-undo-redo.ts | 6 +- .../petrinaut/src/react/use-store.ts | 5 +- .../src/ui/components/arc-item.stories.tsx | 18 +- .../petrinaut/src/ui/components/arc-item.tsx | 19 +- .../petrinaut/src/ui/components/button.tsx | 10 +- .../src/ui/components/dialog.stories.tsx | 36 +- .../petrinaut/src/ui/components/dialog.tsx | 22 +- .../src/ui/components/draft-field-input.tsx | 4 +- .../petrinaut/src/ui/components/drawer.tsx | 38 +- .../src/ui/components/glass-panel.tsx | 5 +- .../petrinaut/src/ui/components/input.tsx | 5 +- .../petrinaut/src/ui/components/menu.tsx | 12 +- .../src/ui/components/number-input.tsx | 5 +- .../src/ui/components/panel-primitives.tsx | 23 +- .../petrinaut/src/ui/components/popover.tsx | 12 +- .../petrinaut/src/ui/components/section.tsx | 28 +- .../ui/components/segment-group.stories.tsx | 16 +- .../src/ui/components/segment-group.tsx | 14 +- .../petrinaut/src/ui/components/select.tsx | 30 +- .../src/ui/components/spreadsheet.stories.tsx | 24 +- .../src/ui/components/spreadsheet.tsx | 100 +- .../petrinaut/src/ui/components/stack.tsx | 4 +- .../horizontal/horizontal-tabs-container.tsx | 12 +- .../vertical/vertical-sub-views-container.tsx | 56 +- .../petrinaut/src/ui/components/table.tsx | 30 +- .../petrinaut/src/ui/components/tooltip.tsx | 15 +- .../src/ui/constants/entity-icons.tsx | 4 +- .../petrinaut/src/ui/constants/ui-subviews.ts | 5 +- .../petrinaut/src/ui/hooks/use-draft-field.ts | 9 +- .../src/ui/lib/calculate-graph-layout.ts | 4 +- .../petrinaut/src/ui/lib/clamp-index.ts | 5 +- .../src/ui/lib/compile-visualizer.ts | 8 +- .../petrinaut/src/ui/lib/hsl-color.ts | 3 +- .../petrinaut/src/ui/lib/split-pascal-case.ts | 4 +- .../petrinaut/src/ui/lib/viewport.test.ts | 5 +- .../petrinaut/src/ui/lib/viewport.ts | 23 +- .../src/ui/monaco/code-editor.stories.tsx | 21 +- .../petrinaut/src/ui/monaco/code-editor.tsx | 16 +- .../src/ui/monaco/completion-sync.tsx | 68 +- .../petrinaut/src/ui/monaco/context.ts | 4 +- .../petrinaut/src/ui/monaco/hover-sync.tsx | 5 +- .../petrinaut/src/ui/monaco/provider.tsx | 14 +- .../src/ui/monaco/signature-help-sync.tsx | 65 +- .../src/ui/petrinaut-story-provider.tsx | 5 +- .../src/ui/resize/use-resize-drag.ts | 12 +- .../components/BottomBar/bottom-bar.tsx | 10 +- .../BottomBar/diagnostics-indicator.tsx | 4 +- .../BottomBar/playback-settings-menu.tsx | 75 +- .../BottomBar/simulation-controls.tsx | 17 +- .../components/BottomBar/toolbar-modes.tsx | 5 +- .../BottomBar/use-keyboard-shortcuts.ts | 36 +- .../components/TopBar/mode-selector.tsx | 5 +- .../running-experiments-popover.stories.tsx | 20 +- .../TopBar/running-experiments-popover.tsx | 13 +- .../Editor/components/TopBar/top-bar.tsx | 18 +- .../src/ui/views/Editor/editor-view.tsx | 27 +- .../views/Editor/panels/BottomPanel/panel.tsx | 34 +- .../BottomPanel/subviews/diagnostics.tsx | 33 +- .../subviews/simulation-settings.tsx | 55 +- .../subviews/simulation-timeline.tsx | 107 +- .../subviews/simulation-timeline/chart.tsx | 55 +- .../subviews/simulation-timeline/header.tsx | 11 +- .../subviews/simulation-timeline/legend.tsx | 6 +- .../subviews/simulation-timeline/main.tsx | 4 +- .../series-config/index.ts | 9 +- .../series-config/per-place.ts | 4 +- .../series-config/per-transition.ts | 3 +- .../series-config/per-type.ts | 8 +- .../simulation-timeline/use-streaming-data.ts | 15 +- .../views/Editor/panels/LeftSideBar/panel.tsx | 19 +- .../subviews/differential-equations-list.tsx | 60 +- .../LeftSideBar/subviews/entities-tree.tsx | 22 +- .../subviews/filterable-list-sub-view.tsx | 62 +- .../LeftSideBar/subviews/nodes-list.tsx | 5 +- .../LeftSideBar/subviews/parameters-list.tsx | 8 +- .../LeftSideBar/subviews/search-panel.tsx | 26 +- .../LeftSideBar/subviews/types-list.tsx | 9 +- .../PropertiesPanel/arc-properties/main.tsx | 36 +- .../context.tsx | 9 +- .../differential-equation-properties/main.tsx | 20 +- .../subviews/main.tsx | 61 +- .../PropertiesPanel/multi-selection-panel.tsx | 4 +- .../Editor/panels/PropertiesPanel/panel.tsx | 37 +- .../parameter-properties/context.tsx | 22 +- .../parameter-properties/main.tsx | 5 +- .../parameter-properties/subviews/main.tsx | 9 +- .../place-properties/context.tsx | 22 +- .../PropertiesPanel/place-properties/main.tsx | 15 +- .../place-properties/subviews/main.tsx | 31 +- .../initial-state-editor.tsx | 12 +- .../subviews/place-initial-state/subview.tsx | 49 +- .../subviews/place-visualizer/subview.tsx | 33 +- .../properties-panel.stories.tsx | 65 +- .../transition-properties/context.tsx | 26 +- .../transition-properties/main.tsx | 5 +- .../transition-properties/subviews/main.tsx | 36 +- .../transition-firing-time/subview.tsx | 8 +- .../subviews/transition-results/subview.tsx | 21 +- .../type-properties/color-select.tsx | 15 +- .../type-properties/context.tsx | 7 +- .../type-properties/subviews/main.tsx | 30 +- .../SimulateView/drawer-error-display.tsx | 5 +- .../experiments/create-experiment-drawer.tsx | 30 +- .../experiments/experiment-timeline.tsx | 25 +- .../experiments-story-fixtures.tsx | 41 +- .../experiments/experiments-view.tsx | 24 +- .../experiments/view-experiment-drawer.tsx | 25 +- .../metrics/create-metric-drawer.tsx | 36 +- .../SimulateView/metrics/metric-form.tsx | 36 +- .../SimulateView/metrics/metric-mapping.ts | 5 +- .../SimulateView/metrics/metrics-view.tsx | 11 +- .../metrics/view-metric-drawer.tsx | 53 +- .../create-scenario-drawer.stories.tsx | 5 +- .../scenarios/create-scenario-drawer.tsx | 23 +- .../SimulateView/scenarios/scenario-form.tsx | 116 +- .../scenarios/scenario-mapping.ts | 9 +- .../SimulateView/scenarios/scenarios-view.tsx | 5 +- .../scenarios/view-scenario-drawer.tsx | 34 +- .../SimulateView/simulate-subview-frame.tsx | 6 +- .../SimulateView/simulate-view.stories.tsx | 19 +- .../panels/SimulateView/simulate-view.tsx | 8 +- .../src/ui/views/Editor/run-auto-layout.ts | 9 +- .../src/ui/views/SDCPN/components/arc.tsx | 27 +- .../SDCPN/components/classic-place-node.tsx | 20 +- .../components/classic-transition-node.tsx | 14 +- .../ui/views/SDCPN/components/mini-map.tsx | 11 +- .../ui/views/SDCPN/components/node-card.tsx | 6 +- .../ui/views/SDCPN/components/place-node.tsx | 16 +- .../SDCPN/components/transition-node.tsx | 18 +- .../SDCPN/components/viewport-controls.tsx | 6 +- .../components/viewport-settings-dialog.tsx | 32 +- .../SDCPN/hooks/use-apply-node-changes.ts | 13 +- .../SDCPN/hooks/use-recenter-on-panel-open.ts | 18 +- .../SDCPN/hooks/use-sdcpn-to-react-flow.ts | 32 +- .../src/ui/views/SDCPN/reactflow-types.ts | 9 +- .../src/ui/views/SDCPN/sdcpn-view.tsx | 50 +- libs/@hashintel/petrinaut/vite.config.ts | 11 +- libs/@hashintel/query-editor/eslint.config.js | 7 +- .../query-editor/src/entity-query-editor.tsx | 19 +- .../src/entity-query-editor/query-form.tsx | 9 +- .../query-form/filter-row.tsx | 21 +- .../filter-row/chain-operator-selector.tsx | 6 +- .../query-form/filter-row/rhf-select.tsx | 19 +- .../query-form/filter-row/type-selector.tsx | 8 +- .../query-form/filter-row/utils.ts | 16 +- .../src/entity-query-editor/query-preview.tsx | 15 +- .../entity-query-editor/readonly-context.tsx | 6 +- .../src/entity-query-editor/types.ts | 19 +- .../src/entity-query-editor/utils.ts | 23 +- libs/@hashintel/query-editor/src/main.ts | 5 +- libs/@hashintel/refractive/.oxlintrc.json | 33 +- .../src/components/composite-parts.tsx | 8 +- .../refractive/src/components/filter.tsx | 23 +- .../src/helpers/split-imagedata-to-parts.ts | 16 +- .../refractive/src/hoc/refractive.tsx | 12 +- .../src/maps/calculate-circle-map.ts | 9 +- .../src/maps/calculate-rounded-square-map.ts | 36 +- .../refractive/src/maps/displacement-map.ts | 8 +- .../refractive/src/maps/specular.ts | 12 +- .../refractive/stories/example-article.tsx | 140 +- libs/@hashintel/refractive/vite.config.ts | 4 +- libs/@hashintel/type-editor/eslint.config.js | 7 +- .../type-editor/src/entity-type-editor.tsx | 17 +- .../entity-type-editor/inheritance-row.tsx | 48 +- .../inheritance-row/inherited-type-card.tsx | 8 +- .../inheritance-row/use-validate-parents.ts | 53 +- .../src/entity-type-editor/link-list-card.tsx | 60 +- .../destination-entity-type-selector.tsx | 32 +- .../destination-type-container.tsx | 5 +- .../link-list-card/inherited-link-row.tsx | 40 +- .../link-list-card/type-chip-label.tsx | 10 +- .../entity-type-editor/property-list-card.tsx | 91 +- .../disabled-checkbox-cell.tsx | 8 +- .../get-property-type-schema.ts | 5 +- .../property-list-card/property-row.tsx | 23 +- .../property-title-cell.tsx | 28 +- .../property-title-cell/tag-icon.tsx | 8 +- .../expected-value-selector.tsx | 141 +- .../custom-expected-value-builder.tsx | 37 +- .../array-expected-value-builder.tsx | 72 +- .../array-min-max-items.tsx | 37 +- .../expected-value-chip.tsx | 3 +- .../shared/custom-expected-value-selector.tsx | 17 +- .../shared/delete-expected-value-modal.tsx | 26 +- .../shared/expected-value-badge.tsx | 21 +- .../shared/expected-value-selector-context.ts | 5 +- .../shared/object-expected-value-builder.tsx | 49 +- ...perty-type-to-form-data-expected-values.ts | 57 +- .../shared/expected-value-types.ts | 5 +- .../shared/get-expected-value-descriptor.ts | 5 +- .../shared/property-type-form-values.ts | 5 +- .../shared/arrow-turn-down-right-icon.tsx | 5 +- .../shared/collapsible-row-line.tsx | 5 +- .../shared/empty-list-card.tsx | 6 +- .../shared/entity-type-table.tsx | 13 +- .../insert-property-field/type-selector.tsx | 4 +- .../shared/insert-type-field.tsx | 10 +- .../src/entity-type-editor/shared/link.tsx | 12 +- .../shared/multiple-values-cell.tsx | 70 +- .../shared/question-icon.tsx | 14 +- .../entity-type-editor/shared/type-form.tsx | 66 +- .../shared/type-menu-cell.tsx | 26 +- .../entity-type-editor/shared/typed-values.ts | 9 +- .../shared/use-filter-type-options.ts | 6 +- .../shared/use-inherited-values.ts | 31 +- .../shared/use-state-callback.ts | 14 +- .../shared/use-type-versions.ts | 3 +- .../shared/version-upgrade-indicator.tsx | 21 +- .../src/get-entity-type-from-form-data.ts | 25 +- .../src/get-form-data-from-entity-type.ts | 9 +- .../src/shared/customization-context.tsx | 4 +- .../src/shared/data-types-options-context.tsx | 27 +- .../shared/entity-types-options-context.tsx | 11 +- .../type-editor/src/shared/form-types.ts | 6 +- .../src/shared/ontology-functions-context.tsx | 8 +- .../shared/property-types-options-context.tsx | 13 +- libs/@local/advanced-types/src/distribute.ts | 12 +- .../advanced-types/src/typed-entries.ts | 13 +- libs/@local/eslint/src/builtIn.ts | 16 +- libs/@local/eslint/src/deprecated/base.ts | 23 +- libs/@local/eslint/src/import.ts | 4 +- libs/@local/eslint/src/jsdoc.ts | 5 +- libs/@local/eslint/src/types.ts | 11 +- libs/@local/eslint/src/typescript.ts | 9 +- .../graph/api/openapi/models/data_type.json | 4 +- .../graph/api/openapi/models/entity_type.json | 14 +- .../api/openapi/models/property_type.json | 4 +- .../api/openapi/models/update_data_type.json | 4 +- .../openapi/models/update_entity_type.json | 4 +- .../openapi/models/update_property_type.json | 13 +- .../api/src/rest/json_schemas/data_type.json | 4 +- .../src/rest/json_schemas/entity_type.json | 14 +- .../src/rest/json_schemas/property_type.json | 4 +- .../rest/json_schemas/update_data_type.json | 4 +- .../rest/json_schemas/update_entity_type.json | 4 +- .../json_schemas/update_property_type.json | 13 +- .../graph/sdk/typescript/eslint.config.js | 5 +- .../graph/sdk/typescript/src/authorization.ts | 6 +- .../graph/sdk/typescript/src/data-type.ts | 66 +- .../graph/sdk/typescript/src/embeddings.ts | 13 +- .../graph/sdk/typescript/src/entity-type.ts | 113 +- .../@local/graph/sdk/typescript/src/entity.ts | 240 +-- .../@local/graph/sdk/typescript/src/filter.ts | 16 +- libs/@local/graph/sdk/typescript/src/harpc.ts | 10 +- .../graph/sdk/typescript/src/ontology.ts | 25 +- .../typescript/src/principal/actor-group.ts | 30 +- .../sdk/typescript/src/principal/actor.ts | 32 +- .../src/principal/hash-instance-admins.ts | 28 +- .../sdk/typescript/src/principal/team.ts | 7 +- .../graph/sdk/typescript/src/principal/web.ts | 23 +- .../graph/sdk/typescript/src/property-type.ts | 57 +- .../graph/sdk/typescript/src/subgraph.ts | 19 +- .../src/user-entity-restrictions.ts | 3 +- .../graph/sdk/typescript/src/validation.ts | 15 +- .../graph/sdk/typescript/tests/entity.test.ts | 75 +- .../type-defs/typescript/status-payloads.ts | 12 +- .../graph/type-defs/typescript/status.ts | 6 +- .../client/typescript/src/ClientError.ts | 16 +- .../typescript/src/binary/MutableBuffer.ts | 43 +- .../typescript/src/binary/MutableBytes.ts | 47 +- .../client/typescript/src/codec/Decoder.ts | 8 +- .../client/typescript/src/codec/Encoder.ts | 8 +- .../typescript/src/codec/JsonDecoder.ts | 14 +- .../typescript/src/codec/JsonEncoder.ts | 9 +- .../harpc/client/typescript/src/net/Client.ts | 15 +- .../harpc/client/typescript/src/net/Config.ts | 5 +- .../client/typescript/src/net/Connection.ts | 51 +- .../typescript/src/net/NetworkLogger.ts | 4 +- .../client/typescript/src/net/Request.ts | 51 +- .../client/typescript/src/net/Response.ts | 19 +- .../client/typescript/src/net/Transaction.ts | 7 +- .../client/typescript/src/net/internal/dns.ts | 33 +- .../typescript/src/net/internal/multiaddr.ts | 10 +- .../src/net/internal/networkLogger.ts | 33 +- .../src/net/internal/peerConnection.ts | 16 +- .../typescript/src/net/internal/transport.ts | 212 +-- .../client/typescript/src/types/ErrorCode.ts | 27 +- .../src/types/ProcedureDescriptor.ts | 22 +- .../typescript/src/types/ProcedureId.ts | 33 +- .../typescript/src/types/ResponseKind.ts | 30 +- .../src/types/SubsystemDescriptor.ts | 18 +- .../typescript/src/types/SubsystemId.ts | 33 +- .../client/typescript/src/types/Version.ts | 15 +- .../harpc/client/typescript/src/utils.ts | 18 +- .../src/wire-protocol/RequestIdProducer.ts | 4 +- .../src/wire-protocol/models/Payload.ts | 25 +- .../src/wire-protocol/models/Protocol.ts | 13 +- .../wire-protocol/models/ProtocolVersion.ts | 24 +- .../wire-protocol/models/request/Request.ts | 24 +- .../models/request/RequestBegin.ts | 11 +- .../models/request/RequestBody.ts | 40 +- .../models/request/RequestFlags.ts | 20 +- .../models/request/RequestFrame.ts | 18 +- .../models/request/RequestHeader.ts | 30 +- .../wire-protocol/models/request/RequestId.ts | 16 +- .../wire-protocol/models/response/Response.ts | 15 +- .../models/response/ResponseBegin.ts | 9 +- .../models/response/ResponseBody.ts | 40 +- .../models/response/ResponseFlags.ts | 12 +- .../models/response/ResponseFrame.ts | 18 +- .../models/response/ResponseHeader.ts | 24 +- .../stream/ResponseFromBytesStream.ts | 18 +- .../tests/binary/MutableBuffer.test.ts | 34 +- .../tests/codec/JsonDecoder.test.ts | 34 +- .../tests/codec/JsonEncoder.test.ts | 9 +- .../typescript/tests/net/Request.test.ts | 18 +- .../tests/wire-protocol/codec.bench.ts | 8 +- .../tests/wire-protocol/decode.test.ts | 69 +- .../tests/wire-protocol/encode.test.ts | 115 +- .../typescript/tests/wire-protocol/utils.ts | 13 +- .../src/create-graph-client.ts | 12 +- .../hash-backend-utils/src/environment.ts | 5 +- libs/@local/hash-backend-utils/src/error.ts | 11 +- .../hash-backend-utils/src/file-storage.ts | 22 +- .../file-storage/aws-s3-storage-provider.ts | 59 +- libs/@local/hash-backend-utils/src/flows.ts | 72 +- .../src/flows/action-types.ts | 8 +- .../src/flows/get-flow-context.ts | 54 +- .../src/flows/get-flow-run-details.ts | 164 +- .../src/flows/payload-storage.ts | 33 +- .../src/flows/process-flow-workflow.ts | 126 +- .../common-activities.ts | 10 +- .../persist-flow-activity.ts | 75 +- .../get-all-steps-in-flow.ts | 4 +- .../get-step-definition-from-flow.ts | 19 +- .../process-flow-workflow/initialize-flow.ts | 20 +- .../pass-outputs-to-unprocessed-steps.ts | 78 +- .../flows/shared/get-flow-run-entity-by-id.ts | 33 +- libs/@local/hash-backend-utils/src/google.ts | 15 +- .../hash-backend-utils/src/hash-instance.ts | 8 +- .../src/integrations/aviation.ts | 5 +- .../integrations/aviation/aero-api/client.ts | 24 +- .../aviation/aero-api/client/build-graph.ts | 4 +- .../aero-api/client/build-graph/aircraft.ts | 16 +- .../aero-api/client/build-graph/airline.ts | 12 +- .../aero-api/client/build-graph/airport.ts | 15 +- .../aero-api/client/build-graph/arrives-at.ts | 18 +- .../client/build-graph/departs-from.ts | 15 +- .../aero-api/client/build-graph/flight.ts | 23 +- .../client/build-graph/mapping-types.ts | 18 +- .../aviation/aero-api/client/provenance.ts | 5 +- .../aviation/flightradar24/client.ts | 4 +- .../aviation/flightradar24/client/flight.ts | 3 +- .../aviation/flightradar24/client/types.ts | 14 +- .../aviation/shared/primary-keys.ts | 93 +- .../src/internal-api-client.ts | 11 +- .../src/linear-type-mappings.ts | 108 +- libs/@local/hash-backend-utils/src/linear.ts | 13 +- .../hash-backend-utils/src/logger.test.ts | 9 +- libs/@local/hash-backend-utils/src/logger.ts | 38 +- .../hash-backend-utils/src/machine-actors.ts | 29 +- .../hash-backend-utils/src/notifications.ts | 17 +- .../src/opentelemetry.test.ts | 9 +- .../hash-backend-utils/src/opentelemetry.ts | 44 +- .../hash-backend-utils/src/queue/redis.ts | 21 +- .../hash-backend-utils/src/service-usage.ts | 189 +- .../@local/hash-backend-utils/src/shutdown.ts | 4 +- .../src/simplified-graph.ts | 62 +- .../temporal-integration-workflow-types.ts | 12 +- .../interceptors/activities/sentry.ts | 8 +- .../src/temporal/worker-bootstrap.ts | 26 +- .../temporal/workflow-span-adapter.test.ts | 14 +- .../src/temporal/workflow-span-adapter.ts | 9 +- .../hash-backend-utils/src/url-validation.ts | 24 +- .../hash-backend-utils/src/user-secret.ts | 28 +- libs/@local/hash-backend-utils/src/vault.ts | 33 +- .../src/ai-inference-types.ts | 26 +- .../src/block-collection.ts | 25 +- .../src/blocks-constants.ts | 6 +- .../hash-isomorphic-utils/src/blocks.ts | 25 +- .../src/create-apollo-client.ts | 29 +- .../src/create-prose-mirror-state.ts | 7 +- .../hash-isomorphic-utils/src/data-types.ts | 64 +- .../src/entity-store-plugin.ts | 158 +- .../hash-isomorphic-utils/src/entity-store.ts | 83 +- .../hash-isomorphic-utils/src/entity.ts | 73 +- .../hash-isomorphic-utils/src/environment.ts | 4 +- .../src/flows/action-definitions.ts | 146 +- .../flows/browser-plugin-flow-definitions.ts | 378 ++-- .../src/flows/browser-plugin-flow-types.ts | 6 +- .../src/flows/example-flow-definitions.ts | 1048 ++++++----- .../src/flows/file-flow-definitions.ts | 118 +- .../src/flows/goal-flow-definitions.ts | 118 +- .../goal-flow-definitions/google-sheets.ts | 20 +- .../goal-flow-definitions/markdown-report.ts | 17 +- .../src/flows/integration-flow-definitions.ts | 403 +++-- .../src/flows/mappings.ts | 59 +- .../src/flows/schedule-types.ts | 3 +- .../src/flows/signals.ts | 6 +- .../src/flows/temporal-types.ts | 14 +- .../src/flows/trigger-definitions.ts | 27 +- .../hash-isomorphic-utils/src/flows/types.ts | 110 +- .../hash-isomorphic-utils/src/flows/util.ts | 75 +- .../src/generate-entity-label.ts | 68 +- .../src/generate-system-types.ts | 6 +- .../src/google-integration.ts | 4 +- .../src/graph-queries.ts | 29 +- .../src/graphql/scalar-mapping.ts | 95 +- .../type-defs/knowledge/entity.typedef.ts | 38 +- .../type-defs/knowledge/flow.typedef.ts | 5 +- .../type-defs/knowledge/org.typedef.ts | 4 +- .../type-defs/ontology/data-type.typedef.ts | 12 +- .../type-defs/ontology/entity-type.typedef.ts | 8 +- .../ontology/property-type.typedef.ts | 4 +- .../hash-isomorphic-utils/src/json-utils.ts | 24 +- .../hash-isomorphic-utils/src/normalize.ts | 3 +- .../hash-isomorphic-utils/src/numbers.ts | 12 +- .../src/ontology-type-ids.ts | 1516 ++++++---------- .../src/ontology-types.ts | 16 +- .../hash-isomorphic-utils/src/organization.ts | 13 +- .../src/page-entity-type-ids.ts | 9 +- .../src/prosemirror-manager.ts | 137 +- .../hash-isomorphic-utils/src/prosemirror.ts | 37 +- .../hash-isomorphic-utils/src/provenance.ts | 21 +- .../src/query-graphql-api.ts | 9 +- .../hash-isomorphic-utils/src/sanitize.ts | 5 +- libs/@local/hash-isomorphic-utils/src/save.ts | 132 +- .../src/service-usage.ts | 83 +- .../src/simplify-properties.ts | 5 +- .../src/stringify-error.ts | 6 +- .../src/stringify-property-value.ts | 4 +- .../src/system-types/academicpaper.ts | 3 +- .../src/system-types/blockprotocol/query.ts | 10 +- .../src/system-types/blockprotocol/thing.ts | 4 +- .../src/system-types/book.ts | 6 +- .../src/system-types/canvas.ts | 32 +- .../src/system-types/claim.ts | 4 +- .../src/system-types/commentnotification.ts | 39 +- .../src/system-types/docxdocument.ts | 9 +- .../src/system-types/facebookaccount.ts | 9 +- .../src/system-types/flight.ts | 27 +- .../src/system-types/githubaccount.ts | 9 +- .../system-types/google/googlesheetsfile.ts | 72 +- .../src/system-types/google/shared.ts | 22 +- .../system-types/graphchangenotification.ts | 15 +- .../src/system-types/hashinstance.ts | 15 +- .../src/system-types/instagramaccount.ts | 9 +- .../src/system-types/linear/attachment.ts | 22 +- .../src/system-types/linear/shared.ts | 82 +- .../src/system-types/linearintegration.ts | 43 +- .../src/system-types/linkedinaccount.ts | 9 +- .../src/system-types/machine.ts | 3 +- .../src/system-types/mentionnotification.ts | 35 +- .../src/system-types/note.ts | 11 +- .../src/system-types/pdfdocument.ts | 9 +- .../src/system-types/petrinet.ts | 3 +- .../src/system-types/pptxpresentation.ts | 9 +- .../src/system-types/shared.ts | 260 +-- .../src/system-types/spreadsheetfile.ts | 9 +- .../src/system-types/studyrecord.ts | 45 +- .../src/system-types/tiktokaccount.ts | 9 +- .../src/system-types/twitteraccount.ts | 9 +- .../src/system-types/usagerecord.ts | 18 +- libs/@local/hash-isomorphic-utils/src/text.ts | 27 +- .../@local/hash-isomorphic-utils/src/types.ts | 7 +- libs/@local/hash-isomorphic-utils/src/util.ts | 8 +- .../src/wrap-entities-plugin.ts | 44 +- .../hash-isomorphic-utils/tsconfig.json | 7 +- .../import-resolver/use-shadowing-let.jsonc | 7 +- .../import-resolver/use-shadowing-use.jsonc | 7 +- .../ui/lowering/name-mangler/diverging.jsonc | 7 +- .../ui/lowering/name-mangler/fn-types.jsonc | 8 +- .../ui/lowering/name-mangler/overwrite.jsonc | 7 +- .../name-mangler/type-generics-nested.jsonc | 7 +- .../re-assign-prelude-diverging.jsonc | 7 +- .../lowering/special-form-expander/fn-4.jsonc | 8 +- .../fn-generics-tuple.jsonc | 8 +- .../lowering/special-form-expander/if-3.jsonc | 7 +- .../special-form-expander/let-4.jsonc | 8 +- .../type-expr-call-intersection.jsonc | 6 +- .../type-expr-call-union.jsonc | 6 +- .../type-expr-tuple.jsonc | 6 +- .../type-generic-constraint.jsonc | 7 +- .../special-form-expander/type-generic.jsonc | 7 +- .../special-form-expander/use-struct.jsonc | 7 +- .../definition/contractive-guarded.jsonc | 7 +- .../definition/env-type-interning.jsonc | 7 +- .../definition/translation-intersection.jsonc | 6 +- .../generic-type-resolution.jsonc | 7 +- .../graph-pipeline-inferred-closure.jsonc | 5 +- .../alias-replacement/complex-mixed.jsonc | 12 +- .../alias-replacement/multiple-aliases.jsonc | 7 +- .../alias-replacement/nested-aliases.jsonc | 7 +- .../preserve-non-alias.jsonc | 7 +- .../qualified-variable-alias.jsonc | 7 +- .../checking/argument-count-mismatch.jsonc | 8 +- .../closure-call-unconstrained-direct.jsonc | 5 +- .../checking/closure-unconstrained.jsonc | 8 +- .../lower/checking/collect-filter-graph.jsonc | 5 +- .../ui/lower/checking/filter-graph.jsonc | 5 +- .../ui/lower/checking/input-multiple.jsonc | 7 +- .../ui/lower/checking/minimal-graph.jsonc | 5 +- .../graph-hoisting/double-hoist-deny.jsonc | 5 +- .../lower/graph-hoisting/double-hoist.jsonc | 13 +- .../hoist-inside-boundary.jsonc | 8 +- .../tests/ui/lower/graph-hoisting/hoist.jsonc | 8 +- .../no-hoist-closure-inside-read.jsonc | 7 +- .../graph-hoisting/no-hoist-closure.jsonc | 7 +- .../ui/lower/graph-hoisting/partial.jsonc | 5 +- .../graph-hoisting/sequential-filter.jsonc | 16 +- .../closure-call-unconstrained-direct.jsonc | 5 +- .../inference/closure-unconstrained.jsonc | 8 +- .../tests/ui/lower/inference/if-test.jsonc | 7 +- .../ui/lower/inference/infer-argument.jsonc | 8 +- .../normalization/binary-operation.jsonc | 6 +- .../ui/lower/normalization/binding-body.jsonc | 7 +- .../lower/normalization/binding-value.jsonc | 7 +- .../tests/ui/lower/normalization/call.jsonc | 8 +- .../lower/normalization/graph-read-head.jsonc | 5 +- .../ui/lower/normalization/if-else.jsonc | 7 +- .../ui/lower/normalization/if-test.jsonc | 7 +- .../ui/lower/normalization/if-then.jsonc | 7 +- .../lower/normalization/nested-and-or.jsonc | 6 +- .../specialization/collect-filter-graph.jsonc | 5 +- .../lower/specialization/filter-graph.jsonc | 5 +- .../lower/specialization/minimal-graph.jsonc | 5 +- .../ui/lower/thunking/dependent-call.jsonc | 7 +- .../tests/ui/lower/thunking/nested-call.jsonc | 8 +- .../tests/ui/lower/thunking/tuple-index.jsonc | 7 +- .../tests/ui/reify/nested-expressions.jsonc | 7 +- .../closure-chain.jsonc | 24 +- .../forwarding-closure.jsonc | 8 +- .../thunk-simple.jsonc | 7 +- .../closure-with-const-branch.jsonc | 7 +- .../pass/cfg_simplify/const-nested-if.jsonc | 7 +- .../cfg_simplify/mixed-const-runtime-if.jsonc | 7 +- .../data-dependency/binary-operation.jsonc | 7 +- .../closure-construction.jsonc | 7 +- .../comparison-operators.jsonc | 7 +- .../data-dependency/deeply-nested-tuple.jsonc | 7 +- .../data-dependency/list-construction.jsonc | 7 +- .../nested-tuple-projection.jsonc | 5 +- .../data-dependency/tuple-construction.jsonc | 7 +- .../data-dependency/tuple-projection.jsonc | 7 +- .../tests/ui/pass/dse/live-in-branch.jsonc | 7 +- .../ui/pass/dse/nested-tuple-projection.jsonc | 7 +- .../closure-env-capture.jsonc | 7 +- .../param-const-agree.jsonc | 7 +- .../param-const-diverge.jsonc | 7 +- .../tuple-projection.jsonc | 7 +- .../ui/pass/inline/excessive-depth.jsonc | 8 +- .../ui/pass/inline/filter-with-ctor.jsonc | 5 +- .../ui/pass/inline/heuristic-inline.jsonc | 16 +- .../ui/pass/inline/too-large-to-inline.jsonc | 8 +- .../inst_simplify/annihilator-and-false.jsonc | 7 +- .../inst_simplify/annihilator-or-true.jsonc | 7 +- .../ui/pass/inst_simplify/const-fold-eq.jsonc | 7 +- .../ui/pass/inst_simplify/const-fold-gt.jsonc | 7 +- .../pass/inst_simplify/const-fold-gte.jsonc | 7 +- .../ui/pass/inst_simplify/const-fold-lt.jsonc | 7 +- .../pass/inst_simplify/const-fold-lte.jsonc | 7 +- .../ui/pass/inst_simplify/const-fold-ne.jsonc | 7 +- .../const-propagation-locals.jsonc | 7 +- .../inst_simplify/identity-and-true.jsonc | 7 +- .../inst_simplify/identity-or-false.jsonc | 7 +- .../cascading-simplification.jsonc | 6 +- .../tests/ui/pass/post_inline/showcase.jsonc | 7 +- .../pre_inline/closure-with-dead-branch.jsonc | 7 +- .../pass/pre_inline/nested-if-constant.jsonc | 7 +- .../pass/pre_inline/nested-let-cleanup.jsonc | 7 +- .../mir/tests/ui/reify/graph-read.jsonc | 5 +- .../hashql/mir/tests/ui/reify/if-else.jsonc | 7 +- .../mir/tests/ui/reify/list-index.jsonc | 7 +- .../mir/tests/ui/reify/nested-let.jsonc | 6 +- .../mir/tests/ui/reify/tuple-index.jsonc | 7 +- .../internal-api-client/typescript/api.ts | 553 ++---- .../internal-api-client/typescript/base.ts | 6 +- .../internal-api-client/typescript/common.ts | 14 +- .../typescript/configuration.ts | 4 +- .../repo-chores/node/scripts/ai-pr-review.ts | 35 +- .../ai-pr-review/add-diff-line-numbers.ts | 10 +- .../ai-pr-review/fix-json-formatting.ts | 18 +- .../ai-pr-review/generate-comment-replies.ts | 40 +- .../ai-pr-review/generate-pr-review.ts | 30 +- .../scripts/ai-pr-review/get-pr-comments.ts | 28 +- .../node/scripts/ai-pr-review/get-pr-info.ts | 21 +- .../scripts/check-license-in-workspaces.ts | 37 +- .../repo-chores/node/scripts/create-block.ts | 7 +- .../repo-chores/node/scripts/list-blocks.ts | 12 +- .../repo-chores/node/scripts/postpublish.ts | 22 +- .../repo-chores/node/scripts/prepublish.ts | 18 +- .../repo-chores/node/scripts/shared/git.ts | 9 +- .../node/scripts/shared/monorepo.ts | 4 +- .../node/scripts/shared/package-infos.ts | 12 +- .../node/scripts/shared/update-json.ts | 10 +- .../node/scripts/skill-management.ts | 7 +- .../node/scripts/skill-management/init.ts | 24 +- .../node/scripts/skill-management/schemas.ts | 40 +- .../node/scripts/skill-management/shared.ts | 5 +- .../node/scripts/skill-management/validate.ts | 13 +- .../node/scripts/symlink-agent-rules.ts | 12 +- libs/@local/status/typescript/README.md | 6 +- .../status/typescript/scripts/codegen.ts | 19 +- libs/@local/status/typescript/src/main.ts | 4 +- .../legacy-base-tsconfig-to-refactor.json | 4 +- scripts/resolve-workspace-ranges.mjs | 18 +- .../config/producers/entity_types/links.json | 4 +- .../graph/test-data/rust/src/entity/book.json | 4 +- .../rust/src/entity_type/church.json | 4 +- .../property_type/contact_information.json | 4 +- .../codegen.config.ts | 3 +- .../src/tests/admin-server.ts | 8 +- .../tests/graph/authorization/policy.test.ts | 129 +- .../graph/knowledge/primitive/entity.test.ts | 129 +- .../knowledge/primitive/link-entity.test.ts | 55 +- .../graph/knowledge/system-types/ai.test.ts | 6 +- .../knowledge/system-types/block.test.ts | 28 +- .../system-types/comment-notification.test.ts | 33 +- .../knowledge/system-types/comment.test.ts | 10 +- .../graph/knowledge/system-types/file.test.ts | 39 +- .../system-types/hash-instance.test.ts | 6 +- .../system-types/mention-notification.test.ts | 58 +- .../system-types/org-membership.test.ts | 34 +- .../graph/knowledge/system-types/org.test.ts | 12 +- .../graph/knowledge/system-types/page.test.ts | 158 +- .../graph/knowledge/system-types/user.test.ts | 68 +- .../ontology/primitive/data-type.test.ts | 96 +- .../ontology/primitive/entity-type.test.ts | 186 +- .../ontology/primitive/property-type.test.ts | 63 +- .../src/tests/setup.ts | 18 +- .../src/tests/subgraph/circular.test.ts | 52 +- .../src/tests/subgraph/friendship.test.ts | 653 +++---- .../src/tests/subgraph/simple.test.ts | 6 +- .../src/tests/util.ts | 27 +- .../hash-backend-integration/vitest.config.ts | 10 +- tests/hash-backend-load/rollup.config.ts | 8 +- .../src/authentication/reauthenticate.ts | 5 +- .../src/authentication/registration.ts | 49 +- .../src/authentication/session.ts | 20 +- tests/hash-backend-load/src/graph/api.ts | 5 +- tests/hash-backend-load/src/graph/user.ts | 19 +- tests/hash-backend-load/src/main.ts | 5 +- .../hash-backend-load/src/tracing/request.ts | 4 +- tests/hash-backend-load/src/tracing/sdk.ts | 40 +- tests/hash-playwright/codegen.config.ts | 3 +- tests/hash-playwright/global-setup.ts | 12 +- tests/hash-playwright/playwright.config.ts | 5 +- .../hash-playwright/tests/account/mfa.spec.ts | 78 +- .../tests/account/password.spec.ts | 32 +- .../tests/account/signin.spec.ts | 5 +- .../tests/account/signup.spec.ts | 26 +- .../tests/extension/browser-plugin.spec.ts | 56 +- .../tests/features/entities-page.spec.ts | 3 +- .../tests/features/entity-editing.spec.ts | 34 +- .../features/entity-type-creation.spec.ts | 13 +- .../tests/features/inbox-page.spec.ts | 46 +- .../tests/features/page-creation.spec.ts | 26 +- .../tests/features/page-navigation.spec.ts | 4 +- .../tests/features/page-readonly-mode.spec.ts | 19 +- .../tests/features/profile-page.spec.ts | 33 +- .../tests/guest/guest-user.spec.ts | 36 +- .../tests/shared/api-queries.ts | 42 +- .../browser-plugin-fixtures/fixtures.ts | 5 +- .../shared/change-sidebar-list-display.ts | 8 +- .../tests/shared/delete-user.ts | 21 +- .../shared/get-kratos-verification-code.ts | 20 +- tests/hash-playwright/tests/shared/runtime.ts | 10 +- .../tests/shared/signup-utils.ts | 22 +- .../tests/shared/test-users.ts | 18 +- .../tests/shared/totp-utils.ts | 10 +- tests/hash-playwright/tsconfig.json | 7 +- tests/hash-playwright/turbo.json | 5 +- turbo.json | 6 +- yarn.config.cjs | 30 +- 2228 files changed, 24437 insertions(+), 50757 deletions(-) diff --git a/.claude/hooks/skill-activation-prompt.test.ts b/.claude/hooks/skill-activation-prompt.test.ts index 749e17d03ba..67d850fb5c3 100644 --- a/.claude/hooks/skill-activation-prompt.test.ts +++ b/.claude/hooks/skill-activation-prompt.test.ts @@ -39,8 +39,7 @@ describe("Skill Activation Snapshots", () => { it("update dependencies", ({ task }) => createSnapshot(task.name)); - it("update Cargo.toml workspace dependencies", ({ task }) => - createSnapshot(task.name)); + it("update Cargo.toml workspace dependencies", ({ task }) => createSnapshot(task.name)); it("improve documentation", ({ task }) => createSnapshot(task.name)); diff --git a/.claude/hooks/skill-activation-prompt.ts b/.claude/hooks/skill-activation-prompt.ts index 2f80bc39702..1596f1fb100 100644 --- a/.claude/hooks/skill-activation-prompt.ts +++ b/.claude/hooks/skill-activation-prompt.ts @@ -132,18 +132,11 @@ function main() { const projectDir = getProjectDir(); debug("Project directory:", projectDir); - const rulesPath = path.join( - projectDir, - ".claude", - "skills", - "skill-rules.json", - ); + const rulesPath = path.join(projectDir, ".claude", "skills", "skill-rules.json"); debug("Loading rules from:", rulesPath); - const rules: SkillRules = JSON.parse( - readFileSync(rulesPath, "utf-8"), - ) as SkillRules; + const rules: SkillRules = JSON.parse(readFileSync(rulesPath, "utf-8")) as SkillRules; debug("Rules loaded, checking", Object.keys(rules.skills).length, "skills"); @@ -162,9 +155,7 @@ function main() { // Keyword matching with fuzzy support if (triggers.keywords) { // Try exact substring match first (most specific) - const exactMatch = triggers.keywords.find((kw) => - prompt.includes(kw.toLowerCase()), - ); + const exactMatch = triggers.keywords.find((kw) => prompt.includes(kw.toLowerCase())); if (exactMatch) { debug(`Skill '${skillName}': MATCHED via exact keyword`, exactMatch); @@ -178,9 +169,7 @@ function main() { // For multi-word keywords, ALL words must fuzzy-match // For single-word keywords, just check if it matches any prompt word if (keywordWords.length === 1) { - return promptWords.some((pWord) => - isFuzzyMatch(keywordWords[0]!, pWord), - ); + return promptWords.some((pWord) => isFuzzyMatch(keywordWords[0]!, pWord)); } // Multi-word: all keyword words must match @@ -190,10 +179,7 @@ function main() { }); if (fuzzyMatch) { - debug( - `Skill '${skillName}': MATCHED via fuzzy keyword`, - fuzzyMatch, - ); + debug(`Skill '${skillName}': MATCHED via fuzzy keyword`, fuzzyMatch); matchType = "keyword"; } else { debug(`Skill '${skillName}': no keyword match`); @@ -204,20 +190,12 @@ function main() { // Intent pattern matching (always check, even if keyword matched) if (triggers.intentPatterns) { try { - const compiledPatterns = compileRegexPatterns( - triggers.intentPatterns, - skillName, - ); + const compiledPatterns = compileRegexPatterns(triggers.intentPatterns, skillName); - const matchedPattern = compiledPatterns.find((cp) => - cp.regex.test(prompt), - ); + const matchedPattern = compiledPatterns.find((cp) => cp.regex.test(prompt)); if (matchedPattern) { - debug( - `Skill '${skillName}': MATCHED via intent pattern`, - matchedPattern.pattern, - ); + debug(`Skill '${skillName}': MATCHED via intent pattern`, matchedPattern.pattern); // Only set matchType to intent if keyword didn't already match // (keywords are more specific and take priority) matchType ??= "intent"; @@ -225,9 +203,7 @@ function main() { debug(`Skill '${skillName}': no intent pattern match`); } } catch (error) { - console.error( - `Warning: Skipping skill '${skillName}' due to invalid regex pattern`, - ); + console.error(`Warning: Skipping skill '${skillName}' due to invalid regex pattern`); console.error(error instanceof Error ? error.message : String(error)); continue; } @@ -249,18 +225,10 @@ function main() { output += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"; // Group by priority - const critical = matchedSkills.filter( - (skill) => skill.config.priority === "critical", - ); - const high = matchedSkills.filter( - (skill) => skill.config.priority === "high", - ); - const medium = matchedSkills.filter( - (skill) => skill.config.priority === "medium", - ); - const low = matchedSkills.filter( - (skill) => skill.config.priority === "low", - ); + const critical = matchedSkills.filter((skill) => skill.config.priority === "critical"); + const high = matchedSkills.filter((skill) => skill.config.priority === "high"); + const medium = matchedSkills.filter((skill) => skill.config.priority === "medium"); + const low = matchedSkills.filter((skill) => skill.config.priority === "low"); if (critical.length > 0) { output += "⚠️ CRITICAL SKILLS (REQUIRED):\n"; @@ -322,9 +290,7 @@ function main() { console.error(`Error: ${error.message}`); if (error.message.includes("ENOENT")) { - console.error( - "\nLikely cause: skill-rules.json not found or project directory incorrect", - ); + console.error("\nLikely cause: skill-rules.json not found or project directory incorrect"); console.error(`Project dir: ${getProjectDir()}`); } diff --git a/.claude/skills/skill-rules.json b/.claude/skills/skill-rules.json index 00bde60a200..b074d0ba9b2 100644 --- a/.claude/skills/skill-rules.json +++ b/.claude/skills/skill-rules.json @@ -29,12 +29,7 @@ "priority": "high", "description": "Rust documentation practices for HASH codebase. Use when writing doc comments, documenting functions/types/traits/modules, creating error sections, using intra-doc links, or following rustdoc conventions.", "promptTriggers": { - "keywords": [ - "rustdoc", - "doc comment", - "documentation", - "intra-doc link" - ], + "keywords": ["rustdoc", "doc comment", "documentation", "intra-doc link"], "intentPatterns": [ "\\bdocument(ing|ation)?\\b.*?\\b(rust|function|type|struct|enum|trait|module)\\b", "\\b(write|add|create)\\b.*?\\bdoc\\s*comment\\b", @@ -142,15 +137,7 @@ "priority": "high", "description": "Git workflow for HASH including branch naming, PR creation, and PR reviews. Use when creating branches, making commits, opening pull requests, or reviewing PRs.", "promptTriggers": { - "keywords": [ - "git", - "branch", - "pull request", - "PR", - "commit", - "merge", - "review" - ], + "keywords": ["git", "branch", "pull request", "PR", "commit", "merge", "review"], "intentPatterns": [ "\\b(create|open|submit|review)\\b.*?\\b(PR|pull request|branch)\\b", "\\b(name|naming)\\b.*?\\bbranch\\b", @@ -214,13 +201,7 @@ "priority": "high", "description": "Guide for creating effective Agent Skills. Use when users want to create a new skill (or update an existing skill) that extends an AI agent's capabilities with specialized knowledge, workflows, or tool integrations. Covers skill structure, YAML frontmatter, trigger configuration, and the 500-line rule.", "promptTriggers": { - "keywords": [ - "skill", - "skill-rules", - "SKILL.md", - "creating skill", - "writing skill" - ], + "keywords": ["skill", "skill-rules", "SKILL.md", "creating skill", "writing skill"], "intentPatterns": [ "\\b(how do|how does|explain)\\b.*?\\bskill\\b", "\\b(create|add|modify|build|write)\\b.*?\\bskill\\b", diff --git a/.claude/skills/testing-hashql/references/testing-strategies.md b/.claude/skills/testing-hashql/references/testing-strategies.md index 420ad368ac1..e2162c15601 100644 --- a/.claude/skills/testing-hashql/references/testing-strategies.md +++ b/.claude/skills/testing-hashql/references/testing-strategies.md @@ -89,13 +89,7 @@ From `libs/@local/hashql/hir/tests/ui/lower/graph-hoisting/hoist.jsonc`: [ "::graph::body::filter", ["::graph::head::entities", ["::graph::tmp::decision_time_now"]], - [ - "fn", - { "#tuple": [] }, - { "#struct": { "vertex": "_" } }, - "_", - ["==", "a", "b"], - ], + ["fn", { "#tuple": [] }, { "#struct": { "vertex": "_" } }, "_", ["==", "a", "b"]], ], ], ], diff --git a/.claude/skills/writing-hashql-jexpr/references/special-forms.md b/.claude/skills/writing-hashql-jexpr/references/special-forms.md index d7d92370f05..e27e9767a03 100644 --- a/.claude/skills/writing-hashql-jexpr/references/special-forms.md +++ b/.claude/skills/writing-hashql-jexpr/references/special-forms.md @@ -386,12 +386,7 @@ Create sum types by combining newtypes with union types: "let", "value", ["Some", { "#literal": 42 }], - [ - "if", - ["==", "value", ["None"]], - { "#literal": "empty" }, - { "#literal": "has value" }, - ], + ["if", ["==", "value", ["None"]], { "#literal": "empty" }, { "#literal": "has value" }], ], ], ], diff --git a/.claude/skills/writing-hashql-jexpr/references/syntax-reference.md b/.claude/skills/writing-hashql-jexpr/references/syntax-reference.md index fe46198441b..316ef48bd5f 100644 --- a/.claude/skills/writing-hashql-jexpr/references/syntax-reference.md +++ b/.claude/skills/writing-hashql-jexpr/references/syntax-reference.md @@ -83,10 +83,7 @@ Use `:` prefix for named/labeled arguments. **Object syntax:** ```jsonc -[ - "greet", - { ":name": { "#literal": "Alice" }, ":greeting": { "#literal": "Hello" } }, -] +["greet", { ":name": { "#literal": "Alice" }, ":greeting": { "#literal": "Hello" } }] ``` **Shorthand string syntax:** diff --git a/.config/_examples/vscode/settings.json b/.config/_examples/vscode/settings.json index ad33066a50f..26bb70401a7 100644 --- a/.config/_examples/vscode/settings.json +++ b/.config/_examples/vscode/settings.json @@ -1,10 +1,5 @@ { - "eslint.validate": [ - "javascript", - "javascriptreact", - "typescript", - "typescriptreact" - ], + "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], "files.associations": { "turbo.json": "jsonc", ".sqlfluff": "toml", diff --git a/.config/_examples/zed/settings.json b/.config/_examples/zed/settings.json index ac07ff67928..ac3ed1c1bcb 100644 --- a/.config/_examples/zed/settings.json +++ b/.config/_examples/zed/settings.json @@ -2,12 +2,7 @@ "file_types": { "TOML": [".sqlfluff"], "JSONC": ["turbo.json"], - "Git Ignore": [ - ".prettierignore", - ".markdownlintignore", - ".dockerignore", - ".sqlfluffignore" - ] + "Git Ignore": [".prettierignore", ".markdownlintignore", ".dockerignore", ".sqlfluffignore"] }, "auto_install_extensions": { "oxc": true diff --git a/.config/agents/rules/zod.md b/.config/agents/rules/zod.md index 2b37ec932a2..da1267c0333 100644 --- a/.config/agents/rules/zod.md +++ b/.config/agents/rules/zod.md @@ -32,10 +32,7 @@ Zod v4 stores metadata in registries (primarily `z.globalRegistry`). Use `.meta( ```typescript // ✅ Correct - .meta() at end of chain -z.string() - .min(1) - .max(100) - .meta({ description: "User's full name", label: "Name" }); +z.string().min(1).max(100).meta({ description: "User's full name", label: "Name" }); // ✅ Correct - .describe() shorthand for description only z.string().email().describe("Primary email address"); diff --git a/apps/hash-ai-worker-ts/scripts/compare-llm-response.ts b/apps/hash-ai-worker-ts/scripts/compare-llm-response.ts index 1d60e7e67bc..38f78f7cd85 100644 --- a/apps/hash-ai-worker-ts/scripts/compare-llm-response.ts +++ b/apps/hash-ai-worker-ts/scripts/compare-llm-response.ts @@ -6,10 +6,7 @@ import { getLlmResponse } from "../src/activities/shared/get-llm-response.js"; import { graphApiClient } from "../src/activities/shared/graph-api-client.js"; import { getAliceUserAccountId } from "../src/shared/testing-utilities/get-alice-user-account-id.js"; -import type { - LlmParams, - LlmResponse, -} from "../src/activities/shared/get-llm-response/types.js"; +import type { LlmParams, LlmResponse } from "../src/activities/shared/get-llm-response/types.js"; import type { CompareLlmResponseConfig } from "./compare-llm-response/types.js"; import type { WebId } from "@blockprotocol/type-system"; @@ -36,9 +33,7 @@ const getCompareLlmResponseConfig = async (params: { }; if (!module.config) { - throw new Error( - `No config object exported in the file: ${configFilePath}`, - ); + throw new Error(`No config object exported in the file: ${configFilePath}`); } return module.config; @@ -62,10 +57,7 @@ const persistCompareLlmResponses = (params: { const resultsFileName = `${resultsDirectory}/${now.toISOString()}.json`; - writeFileSync( - resultsFileName, - JSON.stringify({ llmParams, llmResponses }, null, 2), - ); + writeFileSync(resultsFileName, JSON.stringify({ llmParams, llmResponses }, null, 2)); }; export const compareLlmResponses = async () => { diff --git a/apps/hash-ai-worker-ts/scripts/sanitize-html.ts b/apps/hash-ai-worker-ts/scripts/sanitize-html.ts index 3f3b92b9436..f2bfeb113bc 100644 --- a/apps/hash-ai-worker-ts/scripts/sanitize-html.ts +++ b/apps/hash-ai-worker-ts/scripts/sanitize-html.ts @@ -19,9 +19,7 @@ const __dirname = path.dirname(__filename); const url = process.argv[2] as Url; if (!url) { - console.error( - "No URL provided – usage: `yarn sanitize https://example.com'`", - ); + console.error("No URL provided – usage: `yarn sanitize https://example.com'`"); process.exit(1); } diff --git a/apps/hash-ai-worker-ts/src/activities.ts b/apps/hash-ai-worker-ts/src/activities.ts index 65091c692e2..a1dfa9967c9 100644 --- a/apps/hash-ai-worker-ts/src/activities.ts +++ b/apps/hash-ai-worker-ts/src/activities.ts @@ -32,11 +32,7 @@ import type { PropertyTypeWithMetadata, VersionedUrl, } from "@blockprotocol/type-system"; -import type { - Embedding, - EntityEmbedding, - GraphApi, -} from "@local/hash-graph-client"; +import type { Embedding, EntityEmbedding, GraphApi } from "@local/hash-graph-client"; import type { CreateEmbeddingsParams, CreateEmbeddingsReturn, @@ -46,26 +42,16 @@ import type { OpenAI } from "openai"; export { createGraphActivities } from "./activities/graph.js"; -export const createAiActivities = ({ - graphApiClient, -}: { - graphApiClient: GraphApi; -}) => ({ - async parseTextFromFileActivity( - params: ParseTextFromFileParams, - ): Promise { +export const createAiActivities = ({ graphApiClient }: { graphApiClient: GraphApi }) => ({ + async parseTextFromFileActivity(params: ParseTextFromFileParams): Promise { return parseTextFromFile({ graphApiClient }, params); }, - async createEmbeddingsActivity( - params: CreateEmbeddingsParams, - ): Promise { + async createEmbeddingsActivity(params: CreateEmbeddingsParams): Promise { return createEmbeddings(params); }, - async createDataTypeEmbeddingsActivity(params: { - dataType: DataTypeWithMetadata; - }): Promise<{ + async createDataTypeEmbeddingsActivity(params: { dataType: DataTypeWithMetadata }): Promise<{ embedding: Embedding; usage: OpenAI.CreateEmbeddingResponse.Usage; }> { @@ -143,31 +129,23 @@ export const createAiActivities = ({ } // Fetch all entities by IDs in one query - const { entities } = await queryEntities( - { graphApi: graphApiClient }, - params.authentication, - { - filter: { - any: params.entityIds.map((entityId) => - generateEntityIdFilter({ - entityId, - includeArchived: true, - }), - ), - }, - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts: false, - includePermissions: false, + const { entities } = await queryEntities({ graphApi: graphApiClient }, params.authentication, { + filter: { + any: params.entityIds.map((entityId) => + generateEntityIdFilter({ + entityId, + includeArchived: true, + }), + ), }, - ); + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts: false, + includePermissions: false, + }); for (const entity of entities) { // Skip FlowRun entities due to the size of their property values - if ( - entity.metadata.entityTypeIds.includes( - systemEntityTypes.flowRun.entityTypeId, - ) - ) { + if (entity.metadata.entityTypeIds.includes(systemEntityTypes.flowRun.entityTypeId)) { continue; } @@ -177,28 +155,19 @@ export const createAiActivities = ({ } // Query entity type subgraph to get property types - const { subgraph } = await queryEntityTypeSubgraph( - graphApiClient, - params.authentication, - { - filter: { - any: entity.metadata.entityTypeIds.map( - (entityTypeId: VersionedUrl) => ({ - equal: [ - { path: ["versionedUrl"] }, - { parameter: entityTypeId }, - ], - }), - ), - }, - graphResolveDepths: { - inheritsFrom: 255, - constrainsPropertiesOn: 1, - }, - temporalAxes: currentTimeInstantTemporalAxes, - traversalPaths: [], + const { subgraph } = await queryEntityTypeSubgraph(graphApiClient, params.authentication, { + filter: { + any: entity.metadata.entityTypeIds.map((entityTypeId: VersionedUrl) => ({ + equal: [{ path: ["versionedUrl"] }, { parameter: entityTypeId }], + })), + }, + graphResolveDepths: { + inheritsFrom: 255, + constrainsPropertiesOn: 1, }, - ); + temporalAxes: currentTimeInstantTemporalAxes, + traversalPaths: [], + }); const propertyTypes = getPropertyTypes(subgraph); @@ -207,8 +176,7 @@ export const createAiActivities = ({ if (params.embeddingExclusions) { for (const entityTypeId of entity.metadata.entityTypeIds) { const entityTypeBaseUrl = extractBaseUrl(entityTypeId); - const excludedProperties = - params.embeddingExclusions[entityTypeBaseUrl]; + const excludedProperties = params.embeddingExclusions[entityTypeBaseUrl]; if (excludedProperties) { for (const propertyBaseUrl of excludedProperties) { delete filteredProperties[propertyBaseUrl]; @@ -238,8 +206,7 @@ export const createAiActivities = ({ reset: true, updatedAtTransactionTime: entity.metadata.temporalVersioning.transactionTime.start.limit, - updatedAtDecisionTime: - entity.metadata.temporalVersioning.decisionTime.start.limit, + updatedAtDecisionTime: entity.metadata.temporalVersioning.decisionTime.start.limit, }) .then((response) => response.data); } @@ -256,10 +223,7 @@ export const createAiActivities = ({ getWebPageActivity, async getDereferencedEntityTypesActivity( - params: Omit< - Parameters[0], - "graphApiClient" - >, + params: Omit[0], "graphApiClient">, ) { return getDereferencedEntityTypesActivity({ ...params, @@ -268,10 +232,7 @@ export const createAiActivities = ({ }, async getAiAssistantAccountIdActivity( - params: Omit< - Parameters[0], - "graphApiClient" - >, + params: Omit[0], "graphApiClient">, ) { return getAiAssistantAccountIdActivity({ ...params, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities.ts index 1f0b2f6c381..8e149739c97 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities.ts @@ -17,9 +17,11 @@ import type { CreateFlowActivities } from "@local/hash-backend-utils/flows"; import type { VaultClient } from "@local/hash-backend-utils/vault"; import type { AiFlowActionDefinitionId } from "@local/hash-isomorphic-utils/flows/action-definitions"; -export const createFlowActionActivities: CreateFlowActivities< - AiFlowActionDefinitionId -> = ({ vaultClient }: { vaultClient: VaultClient }) => ({ +export const createFlowActionActivities: CreateFlowActivities = ({ + vaultClient, +}: { + vaultClient: VaultClient; +}) => ({ generateWebQueriesAction, webSearchAction, getWebPageByUrlAction, @@ -39,11 +41,7 @@ export const createFlowActionActivities: CreateFlowActivities< }, }); -export const createFlowActivities = ({ - vaultClient, -}: { - vaultClient: VaultClient; -}) => ({ +export const createFlowActivities = ({ vaultClient }: { vaultClient: VaultClient }) => ({ ...createFlowActionActivities({ vaultClient }), generateFlowRunName, }); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/answer-question-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/answer-question-action.ts index ce691f2d251..eb75658af0f 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/answer-question-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/answer-question-action.ts @@ -70,8 +70,7 @@ const answerTools: LlmToolDefinition[] = [ }, confidence: { type: "number", - description: - "Confidence score of the answer, expressed as a number between 0 and 1.", + description: "Confidence score of the answer, expressed as a number between 0 and 1.", }, }, required: ["explanation"], @@ -165,8 +164,7 @@ const callModel = async ( outputs: AiActionStepOutput<"answerQuestion">[]; }> > => { - const { flowEntityId, userAuthentication, stepId, webId } = - await getFlowContext(); + const { flowEntityId, userAuthentication, stepId, webId } = await getFlowContext(); const llmResponse = await getLlmResponse( { @@ -303,10 +301,7 @@ const callModel = async ( `Model is running code with explanation:\n\n${explanation}\n\nThe code:\n${code}\n`, ); - const { stdout, stderr, artifacts } = await runPythonCode( - code, - context, - ); + const { stdout, stderr, artifacts } = await runPythonCode(code, context); const toolResponseMessage = stderr ? `The code you provided generated an error, and you now work to fix it: ${stderr}` @@ -372,11 +367,7 @@ const callModel = async ( if (responseMessages.length) { return callModel( - [ - ...messages, - ...mapLlmMessageToOpenAiMessages({ message }), - ...responseMessages, - ], + [...messages, ...mapLlmMessageToOpenAiMessages({ message }), ...responseMessages], context, codeUsed, iteration + 1, @@ -390,20 +381,14 @@ const callModel = async ( }; return callModel( - [ - ...messages, - ...mapLlmMessageToOpenAiMessages({ message }), - responseMessage, - ], + [...messages, ...mapLlmMessageToOpenAiMessages({ message }), responseMessage], context, codeUsed, iteration + 1, ); }; -export const answerQuestionAction: AiFlowActionActivity< - "answerQuestion" -> = async ({ inputs }) => { +export const answerQuestionAction: AiFlowActionActivity<"answerQuestion"> = async ({ inputs }) => { const { context, entities: entitiesInput, @@ -417,11 +402,7 @@ export const answerQuestionAction: AiFlowActionActivity< // Resolve the stored ref to get the array of PersistedEntitiesMetadata const inputEntities = entitiesInput - ? await resolvePayloadValue( - getStorageProvider(), - "PersistedEntitiesMetadata", - entitiesInput, - ) + ? await resolvePayloadValue(getStorageProvider(), "PersistedEntitiesMetadata", entitiesInput) : undefined; const entities = inputEntities @@ -454,9 +435,7 @@ export const answerQuestionAction: AiFlowActionActivity< equal: [ { path: ["uuid"] }, { - parameter: extractEntityUuidFromEntityId( - entity.metadata.recordId.entityId, - ), + parameter: extractEntityUuidFromEntityId(entity.metadata.recordId.entityId), }, ], })), @@ -498,8 +477,7 @@ export const answerQuestionAction: AiFlowActionActivity< }, ); - const { entities: simpleEntities, entityTypes: simpleTypes } = - getSimpleGraph(subgraph); + const { entities: simpleEntities, entityTypes: simpleTypes } = getSimpleGraph(subgraph); contextToUpload = JSON.stringify({ entities: simpleEntities, @@ -513,10 +491,7 @@ export const answerQuestionAction: AiFlowActionActivity< const requestId = Context.current().info.workflowExecution.workflowId; const sandbox = await Sandbox.create({ template: "base" }); - contextFilePath = await sandbox.uploadFile( - Buffer.from(contextToUpload), - requestId, - ); + contextFilePath = await sandbox.uploadFile(Buffer.from(contextToUpload), requestId); await sandbox.close(); } @@ -524,9 +499,7 @@ export const answerQuestionAction: AiFlowActionActivity< const messages: OpenAI.ChatCompletionCreateParams["messages"] = [ { role: "user", - content: dedent( - `The question your boss asks about the data: ${question}`, - ), + content: dedent(`The question your boss asks about the data: ${question}`), }, ]; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-flow-run-name-activity.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-flow-run-name-activity.ts index 8b146f1b2ce..c7402b34bb1 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-flow-run-name-activity.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-flow-run-name-activity.ts @@ -77,23 +77,15 @@ const getModelSuggestedFlowRunName = async ( const text = getTextContentFromLlmMessage({ message: llmResponse.message }); if (!text) { - throw new Error( - `Failed to generate flow run name: no text content found in LLM message`, - ); + throw new Error(`Failed to generate flow run name: no text content found in LLM message`); } return text; }; -const outputKindsToIgnore: PayloadKind[] = [ - "GoogleSheet", - "GoogleAccountId", - "EntityId", -]; +const outputKindsToIgnore: PayloadKind[] = ["GoogleSheet", "GoogleAccountId", "EntityId"]; -export const generateFlowRunName = async ( - params: GenerateFlowRunNameActivityParams, -) => { +export const generateFlowRunName = async (params: GenerateFlowRunNameActivityParams) => { const { flowDefinition, flowTrigger } = params; if ( @@ -114,15 +106,13 @@ export const generateFlowRunName = async ( } return `${ - flowDefinition.flowDefinitionId === - automaticBrowserInferenceFlowDefinition.flowDefinitionId + flowDefinition.flowDefinitionId === automaticBrowserInferenceFlowDefinition.flowDefinitionId ? "Auto-analyze" : "Analyze" } webpage: ${webPage.url}`; } - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const usageTrackingParams: UsageTrackingParams = { customMetadata: { taskName: "name-flow", stepId }, @@ -134,8 +124,7 @@ export const generateFlowRunName = async ( if (goalFlowDefinitionIds.includes(flowDefinition.flowDefinitionId)) { const researchBrief = flowTrigger.outputs?.find( - ({ outputName }) => - outputName === ("Research guidance" satisfies GoalFlowTriggerInput), + ({ outputName }) => outputName === ("Research guidance" satisfies GoalFlowTriggerInput), )?.payload.value as PayloadKindValues["Text"] | undefined; if (!researchBrief) { @@ -166,8 +155,5 @@ export const generateFlowRunName = async ( workflowDescriptionString += ` The workflow run to be named has no inputs.`; } - return getModelSuggestedFlowRunName( - workflowDescriptionString, - usageTrackingParams, - ); + return getModelSuggestedFlowRunName(workflowDescriptionString, usageTrackingParams); }; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-web-queries-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-web-queries-action.ts index 40f80e9c5ac..00ce44042b8 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-web-queries-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/generate-web-queries-action.ts @@ -42,9 +42,9 @@ type ProposeQueryFunctionCallArguments = { query: string; }; -export const generateWebQueriesAction: AiFlowActionActivity< - "generateWebQueries" -> = async ({ inputs }) => { +export const generateWebQueriesAction: AiFlowActionActivity<"generateWebQueries"> = async ({ + inputs, +}) => { const { prompt, model } = getSimplifiedAiFlowActionInputs({ inputs, actionType: "generateWebQueries", @@ -58,8 +58,7 @@ export const generateWebQueriesAction: AiFlowActionActivity< }; } - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const llmResponse = await getLlmResponse( { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-file-from-url-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-file-from-url-action.ts index 7214a93544c..891225cb498 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-file-from-url-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-file-from-url-action.ts @@ -8,9 +8,7 @@ import { createFileEntityFromUrl } from "./shared/create-file-entity-from-url.js import type { AiFlowActionActivity } from "@local/hash-backend-utils/flows"; -export const getFileFromUrlAction: AiFlowActionActivity< - "getFileFromUrl" -> = async ({ inputs }) => { +export const getFileFromUrlAction: AiFlowActionActivity<"getFileFromUrl"> = async ({ inputs }) => { const { description, displayName, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-by-url-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-by-url-action.ts index 8825ef3943b..201b64f65e6 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-by-url-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-by-url-action.ts @@ -6,9 +6,9 @@ import { getWebPageActivity } from "../get-web-page-activity.js"; import type { Url } from "@blockprotocol/type-system"; import type { AiFlowActionActivity } from "@local/hash-backend-utils/flows"; -export const getWebPageByUrlAction: AiFlowActionActivity< - "getWebPageByUrl" -> = async ({ inputs }) => { +export const getWebPageByUrlAction: AiFlowActionActivity<"getWebPageByUrl"> = async ({ + inputs, +}) => { const { url } = getSimplifiedAiFlowActionInputs({ inputs, actionType: "getWebPageByUrl", diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ai.test.ts index 23cc441661d..c9110cbd83c 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ai.test.ts @@ -16,15 +16,12 @@ test( const status = await getWebPageSummaryAction({ inputs: [ { - inputName: - "url" satisfies InputNameForAiFlowAction<"getWebPageSummary">, + inputName: "url" satisfies InputNameForAiFlowAction<"getWebPageSummary">, payload: { kind: "Text", value: url }, }, ...actionDefinitions.getWebPageSummary.inputs.flatMap( ({ name, default: defaultValue }) => - !defaultValue || name === "url" - ? [] - : [{ inputName: name, payload: defaultValue }], + !defaultValue || name === "url" ? [] : [{ inputName: name, payload: defaultValue }], ), ], }); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ts index 0f0b5cfa2e4..c0abdb076e3 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/get-web-page-summary-action.ts @@ -14,9 +14,7 @@ import { inferenceModelAliasToSpecificModel } from "../shared/inference-model-al import type { Url } from "@blockprotocol/type-system"; import type { AiFlowActionActivity } from "@local/hash-backend-utils/flows"; -const generateSummarizeWebPageSystemPrompt = (params: { - numberOfSentences: number; -}): string => +const generateSummarizeWebPageSystemPrompt = (params: { numberOfSentences: number }): string => dedent(` You are a Web Page Summarizer. The user provides you with the URL, the title, and the HTML content of a web page, @@ -30,9 +28,9 @@ const generateSummarizeWebPageSystemPrompt = (params: { - 'The page mentions products relating to Y' `); -export const getWebPageSummaryAction: AiFlowActionActivity< - "getWebPageSummary" -> = async ({ inputs }) => { +export const getWebPageSummaryAction: AiFlowActionActivity<"getWebPageSummary"> = async ({ + inputs, +}) => { const { url, model, numberOfSentences } = getSimplifiedAiFlowActionInputs({ inputs, actionType: "getWebPageSummary", @@ -62,8 +60,7 @@ export const getWebPageSummaryAction: AiFlowActionActivity< numberOfSentences: numberOfSentences!, }); - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const llmResponse = await getLlmResponse( { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-entities-from-content-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-entities-from-content-action.ts index 85b36e0bda2..ebbcdc085f3 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-entities-from-content-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-entities-from-content-action.ts @@ -1,12 +1,6 @@ -import { - currentTimestamp, - entityIdFromComponents, -} from "@blockprotocol/type-system"; +import { currentTimestamp, entityIdFromComponents } from "@blockprotocol/type-system"; import { typedKeys } from "@local/advanced-types/typed-entries"; -import { - getStorageProvider, - storePayload, -} from "@local/hash-backend-utils/flows/payload-storage"; +import { getStorageProvider, storePayload } from "@local/hash-backend-utils/flows/payload-storage"; import { isInferenceModelName } from "@local/hash-isomorphic-utils/ai-inference-types"; import { getSimplifiedAiFlowActionInputs } from "@local/hash-isomorphic-utils/flows/action-definitions"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; @@ -65,22 +59,24 @@ export const inferEntitiesFromContentAction: AiFlowActionActivity< }; } - const dereferencedEntityTypesWithExistingEntitiesTypes = - await getDereferencedEntityTypesActivity({ + const dereferencedEntityTypesWithExistingEntitiesTypes = await getDereferencedEntityTypesActivity( + { graphApiClient, entityTypeIds, actorId: userAuthentication.actorId, - }); + }, + ); - const entityTypes = Object.entries( - dereferencedEntityTypesWithExistingEntitiesTypes, - ).reduce((acc, [entityTypeId, entityType]) => { - if (entityTypeIds.includes(entityTypeId as VersionedUrl)) { - acc[entityTypeId as VersionedUrl] = entityType; - } + const entityTypes = Object.entries(dereferencedEntityTypesWithExistingEntitiesTypes).reduce( + (acc, [entityTypeId, entityType]) => { + if (entityTypeIds.includes(entityTypeId as VersionedUrl)) { + acc[entityTypeId as VersionedUrl] = entityType; + } - return acc; - }, {} as DereferencedEntityTypesByTypeId); + return acc; + }, + {} as DereferencedEntityTypesByTypeId, + ); let webPageInferenceState: InferenceState = { iterationCount: 1, @@ -160,8 +156,7 @@ export const inferEntitiesFromContentAction: AiFlowActionActivity< ).flatMap(([entityTypeId, proposedEntitiesByType]) => proposedEntitiesByType.map((proposal) => { const summary = webPageInferenceState.proposedEntitySummaries.find( - (proposedEntitySummary) => - proposedEntitySummary.entityId === proposal.entityId, + (proposedEntitySummary) => proposedEntitySummary.entityId === proposal.entityId, )?.summary; const provenance: ProposedEntity["provenance"] = { @@ -182,9 +177,7 @@ export const inferEntitiesFromContentAction: AiFlowActionActivity< }, summary, properties: proposal.properties ?? {}, - propertyMetadata: typedKeys( - proposal.properties ?? {}, - ).reduce( + propertyMetadata: typedKeys(proposal.properties ?? {}).reduce( (acc, propertyKey) => { acc.value[propertyKey] = { metadata: { dataTypeId: null, provenance: { sources: [source] } }, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action.ts index e173e011076..e6cd55bca54 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action.ts @@ -2,10 +2,7 @@ import { Context } from "@temporalio/activity"; import PDFParser from "pdf2json"; import { extractEntityUuidFromEntityId } from "@blockprotocol/type-system"; -import { - getStorageProvider, - storePayload, -} from "@local/hash-backend-utils/flows/payload-storage"; +import { getStorageProvider, storePayload } from "@local/hash-backend-utils/flows/payload-storage"; import { getSimplifiedAiFlowActionInputs } from "@local/hash-isomorphic-utils/flows/action-definitions"; import { blockProtocolPropertyTypes, @@ -125,9 +122,7 @@ export const inferMetadataFromDocumentAction: AiFlowActionActivity< documentEntity, async ({ fileSystemPath }) => { const documentJson = await new Promise((resolve, reject) => { - pdfParser.on("pdfParser_dataError", (errData) => - reject(errData.parserError), - ); + pdfParser.on("pdfParser_dataError", (errData) => reject(errData.parserError)); pdfParser.on("pdfParser_dataReady", (pdfData) => { resolve(pdfData); @@ -171,8 +166,9 @@ export const inferMetadataFromDocumentAction: AiFlowActionActivity< "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/" ]!; - const title = properties.value[systemPropertyTypes.title.propertyTypeBaseUrl] - ?.value as string | undefined; + const title = properties.value[systemPropertyTypes.title.propertyTypeBaseUrl]?.value as + | string + | undefined; const sourceProvenance: SourceProvenance = { type: "document", @@ -232,15 +228,14 @@ export const inferMetadataFromDocumentAction: AiFlowActionActivity< }, ]); - const proposedEntities = - await generateDocumentProposedEntitiesAndCreateClaims({ - aiAssistantAccountId, - documentEntityId, - documentMetadata: { authors }, - documentTitle: title ?? filename, - provenance, - propertyProvenance, - }); + const proposedEntities = await generateDocumentProposedEntitiesAndCreateClaims({ + aiAssistantAccountId, + documentEntityId, + documentMetadata: { authors }, + documentTitle: title ?? filename, + provenance, + propertyProvenance, + }); // Store the proposed entities in S3 to avoid passing large payloads through Temporal const storedRef = await storePayload({ diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-property-patches.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-property-patches.ts index a2f4093e86b..e88198bf3cc 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-property-patches.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-property-patches.ts @@ -27,8 +27,7 @@ export const generateDocumentPropertyPatches = ({ property: { value: numberOfPages, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", provenance, }, } satisfies NumberOfPagesPropertyValueWithMetadata, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-proposed-entities-and-claims.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-proposed-entities-and-claims.ts index adc1638e314..461eb32872a 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-proposed-entities-and-claims.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/generate-proposed-entities-and-claims.ts @@ -66,19 +66,16 @@ const createClaim = async ({ provenance, properties: { value: { - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/": - { - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - provenance: propertyProvenance, - }, - value: claimText, + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/": { + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + provenance: propertyProvenance, }, + value: claimText, + }, "https://hash.ai/@h/types/property-type/subject/": { metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", provenance: propertyProvenance, }, value: subjectText, @@ -86,8 +83,7 @@ const createClaim = async ({ "https://hash.ai/@h/types/property-type/object/": { metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", provenance: propertyProvenance, }, value: objectText, @@ -121,16 +117,14 @@ export const generateDocumentProposedEntitiesAndCreateClaims = async ({ const { createEntitiesAsDraft, webId } = await getFlowContext(); const textDataTypeMetadata: TextDataTypeMetadata = { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", provenance: propertyProvenance, }; const nameOnlyPropertyMetadata: PropertyObjectMetadata = { value: { [blockProtocolPropertyTypes.name.propertyTypeBaseUrl]: { - metadata: - textDataTypeMetadata satisfies NamePropertyValueWithMetadata["metadata"], + metadata: textDataTypeMetadata satisfies NamePropertyValueWithMetadata["metadata"], }, }, }; @@ -149,14 +143,11 @@ export const generateDocumentProposedEntitiesAndCreateClaims = async ({ ) as typeof nameOnlyPropertyMetadata; const authorProperties: PersonProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - authorName, + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": authorName, }; if (email) { - authorProperties["https://hash.ai/@h/types/property-type/email/"] = [ - email, - ]; + authorProperties["https://hash.ai/@h/types/property-type/email/"] = [email]; authorPropertyMetadata.value[systemDataTypes.email.dataTypeBaseUrl] = { value: [ { @@ -233,10 +224,7 @@ export const generateDocumentProposedEntitiesAndCreateClaims = async ({ proposedEntities.push({ claims: emptyClaims, entityTypeIds: [systemLinkEntityTypes.authoredBy.linkEntityTypeId], - localEntityId: entityIdFromComponents( - webId, - generateUuid() as EntityUuid, - ), + localEntityId: entityIdFromComponents(webId, generateUuid() as EntityUuid), properties: {}, propertyMetadata: { value: {} }, provenance, @@ -250,20 +238,14 @@ export const generateDocumentProposedEntitiesAndCreateClaims = async ({ for (const affiliateName of affiliatedWith ?? []) { let institutionEntityId = institutionEntityIdByName[affiliateName]; let institutionProposedEntity = institutionEntityId - ? proposedEntities.find( - (entity) => entity.localEntityId === institutionEntityId, - ) + ? proposedEntities.find((entity) => entity.localEntityId === institutionEntityId) : null; - institutionEntityId ??= entityIdFromComponents( - webId, - generateUuid() as EntityUuid, - ); + institutionEntityId ??= entityIdFromComponents(webId, generateUuid() as EntityUuid); if (!institutionProposedEntity) { const properties: InstitutionProperties = { - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - affiliateName, + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": affiliateName, }; institutionProposedEntity = { @@ -297,13 +279,9 @@ export const generateDocumentProposedEntitiesAndCreateClaims = async ({ subjectText: authorName, }); - authorProposedEntity.claims.isSubjectOf.push( - authorToInstitutionClaim.entityId, - ); + authorProposedEntity.claims.isSubjectOf.push(authorToInstitutionClaim.entityId); - institutionProposedEntity.claims.isSubjectOf.push( - authorToInstitutionClaim.entityId, - ); + institutionProposedEntity.claims.isSubjectOf.push(authorToInstitutionClaim.entityId); /** * Propose the link between the person and the institution entity @@ -311,10 +289,7 @@ export const generateDocumentProposedEntitiesAndCreateClaims = async ({ proposedEntities.push({ claims: emptyClaims, entityTypeIds: [systemLinkEntityTypes.affiliatedWith.linkEntityTypeId], - localEntityId: entityIdFromComponents( - webId, - generateUuid() as EntityUuid, - ), + localEntityId: entityIdFromComponents(webId, generateUuid() as EntityUuid), properties: {}, propertyMetadata: { value: {} }, provenance, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/get-llm-analysis-of-doc.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/get-llm-analysis-of-doc.ts index 7a522130761..b2e8468db62 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/get-llm-analysis-of-doc.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/infer-metadata-from-document-action/get-llm-analysis-of-doc.ts @@ -32,10 +32,7 @@ import { import { graphApiClient } from "../../shared/graph-api-client.js"; import { judgeAiOutputs } from "../../shared/judge-ai-outputs.js"; -import type { - LlmParams, - LlmToolDefinition, -} from "../../shared/get-llm-response/types.js"; +import type { LlmParams, LlmToolDefinition } from "../../shared/get-llm-response/types.js"; import type { EntityId, PropertyObjectWithMetadata, @@ -48,23 +45,14 @@ import type { import type { HashEntity } from "@local/hash-graph-sdk/entity"; import type { File } from "@local/hash-isomorphic-utils/system-types/shared"; -const generateOutputSchema = ( - dereferencedDocEntityTypes: DereferencedEntityType[], -) => { +const generateOutputSchema = (dereferencedDocEntityTypes: DereferencedEntityType[]) => { return { type: "object", additionalProperties: false as const, properties: { documentMetadata: { anyOf: dereferencedDocEntityTypes.map( - ({ - labelProperty: _, - links: __, - title, - $id, - properties, - required, - }) => { + ({ labelProperty: _, links: __, title, $id, properties, required }) => { return { type: "object", title, @@ -138,8 +126,7 @@ const assertIsLlmResponseDocumentData: ( throw new Error("input.documentMetadata is not an object"); } - const { entityTypeId } = - input.documentMetadata as DocumentData["documentMetadata"]; + const { entityTypeId } = input.documentMetadata as DocumentData["documentMetadata"]; if (typeof entityTypeId !== "string") { throw new Error("input.documentMetadata.entityTypeId is not a string"); @@ -158,9 +145,7 @@ const addMetadataToPropertyValue = ( const propertyTypeBaseUrl = propertyMappings[key]; if (!propertyTypeBaseUrl) { - throw new Error( - `Simplified property type mapping for key ${key} not found`, - ); + throw new Error(`Simplified property type mapping for key ${key} not found`); } const propertyType = ( @@ -168,16 +153,12 @@ const addMetadataToPropertyValue = ( )[key]; if (!propertyType) { - throw new Error( - `Property type for key ${key} not found in dereferenced entity type`, - ); + throw new Error(`Property type for key ${key} not found in dereferenced entity type`); } const isArray = "items" in propertyType; - const propertyTypeOneOf = isArray - ? propertyType.items.oneOf - : propertyType.oneOf; + const propertyTypeOneOf = isArray ? propertyType.items.oneOf : propertyType.oneOf; if (propertyTypeOneOf.length !== 1) { throw new Error( @@ -273,9 +254,7 @@ const addMetadataToPropertyValue = ( const nestedBaseUrl = propertyMappings[nestedKey]; if (!nestedBaseUrl) { - throw new Error( - `Simplified property type mapping for key ${nestedKey} not found`, - ); + throw new Error(`Simplified property type mapping for key ${nestedKey} not found`); } return [ @@ -336,14 +315,10 @@ const unsimplifyDocumentMetadata = ( const { entityTypeId, ...properties } = documentMetadata; - const docEntityType = docEntityTypes.find( - (type) => type.schema.$id === entityTypeId, - ); + const docEntityType = docEntityTypes.find((type) => type.schema.$id === entityTypeId); if (!docEntityType) { - throw new Error( - `Dereferenced entity type for entityTypeId ${entityTypeId} not found`, - ); + throw new Error(`Dereferenced entity type for entityTypeId ${entityTypeId} not found`); } const title = properties.title as string | undefined; @@ -364,23 +339,19 @@ const unsimplifyDocumentMetadata = ( }; for (const [key, value] of Object.entries(properties)) { - const propertyTypeBaseUrl = - docEntityType.simplifiedPropertyTypeMappings[key]; + const propertyTypeBaseUrl = docEntityType.simplifiedPropertyTypeMappings[key]; if (!propertyTypeBaseUrl) { - throw new Error( - `Simplified property type mapping for key ${key} not found`, - ); + throw new Error(`Simplified property type mapping for key ${key} not found`); } - fullPropertiesWithDataTypeIds.value[propertyTypeBaseUrl] = - addMetadataToPropertyValue( - key, - value, - docEntityType.simplifiedPropertyTypeMappings, - docEntityType.schema.properties, - propertyProvenance, - ); + fullPropertiesWithDataTypeIds.value[propertyTypeBaseUrl] = addMetadataToPropertyValue( + key, + value, + docEntityType.simplifiedPropertyTypeMappings, + docEntityType.schema.properties, + propertyProvenance, + ); } return { @@ -397,37 +368,32 @@ export const getLlmAnalysisOfDoc = async ({ }: { fileEntity: HashEntity; }): Promise => { - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); - - const docsEntityType = await queryEntityTypeSubgraph( - graphApiClient, - userAuthentication, - { - filter: { - all: [ - { - equal: [ - { - path: ["inheritsFrom", "*", "versionedUrl"], - }, - { - parameter: systemEntityTypes.doc.entityTypeId, - }, - ], - }, - ], - }, + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); + + const docsEntityType = await queryEntityTypeSubgraph(graphApiClient, userAuthentication, { + filter: { + all: [ + { + equal: [ + { + path: ["inheritsFrom", "*", "versionedUrl"], + }, + { + parameter: systemEntityTypes.doc.entityTypeId, + }, + ], + }, + ], + }, - temporalAxes: currentTimeInstantTemporalAxes, - graphResolveDepths: { - ...almostFullOntologyResolveDepths, - constrainsLinkDestinationsOn: 4, - constrainsLinksOn: 4, - }, - traversalPaths: [], + temporalAxes: currentTimeInstantTemporalAxes, + graphResolveDepths: { + ...almostFullOntologyResolveDepths, + constrainsLinkDestinationsOn: 4, + constrainsLinksOn: 4, }, - ); + traversalPaths: [], + }); // const docEntityTypes const dereferencedDocEntityTypes = getEntityTypes(docsEntityType.subgraph) @@ -445,9 +411,7 @@ export const getLlmAnalysisOfDoc = async ({ ); }); - const schema = generateOutputSchema( - dereferencedDocEntityTypes.map((type) => type.schema), - ); + const schema = generateOutputSchema(dereferencedDocEntityTypes.map((type) => type.schema)); const textContent: LlmMessageTextContent = { type: "text", @@ -557,20 +521,12 @@ export const getLlmAnalysisOfDoc = async ({ judgeModel: "gemini-1.5-pro-002", }); - for (const { - correctionType, - jsonPath, - correctValue, - } of judgeVerdict.corrections) { + for (const { correctionType, jsonPath, correctValue } of judgeVerdict.corrections) { if (correctionType === "delete-unfounded") { unset(response.message, jsonPath); - logger.info( - `Judge correction: remove property ${jsonPath.slice(3).join(".")} from output`, - ); + logger.info(`Judge correction: remove property ${jsonPath.slice(3).join(".")} from output`); } else { - const previousValue = get(response.message, jsonPath) as - | PropertyValue - | undefined; + const previousValue = get(response.message, jsonPath) as PropertyValue | undefined; set(response.message, jsonPath, correctValue); @@ -580,15 +536,11 @@ export const getLlmAnalysisOfDoc = async ({ } } - return unsimplifyDocumentMetadata( - toolCall.input, - dereferencedDocEntityTypes, - { - entityId: fileEntity.entityId, - fileUrl: - fileEntity.properties[ - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/" - ], - }, - ); + return unsimplifyDocumentMetadata(toolCall.input, dereferencedDocEntityTypes, { + entityId: fileEntity.entityId, + fileUrl: + fileEntity.properties[ + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/" + ], + }); }; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entities-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entities-action.ts index 03b70558a48..7e22d247cf3 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entities-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entities-action.ts @@ -20,16 +20,15 @@ import type { ProposedEntityWithResolvedLinks, } from "@local/hash-isomorphic-utils/flows/types"; -export const persistEntitiesAction: AiFlowActionActivity< - "persistEntities" -> = async ({ inputs }) => { +export const persistEntitiesAction: AiFlowActionActivity<"persistEntities"> = async ({ + inputs, +}) => { const { runId, stepId, workflowId } = await getFlowContext(); - const { draft, proposedEntities: proposedEntitiesInput } = - getSimplifiedAiFlowActionInputs({ - inputs, - actionType: "persistEntities", - }); + const { draft, proposedEntities: proposedEntitiesInput } = getSimplifiedAiFlowActionInputs({ + inputs, + actionType: "persistEntities", + }); const proposedEntities = await resolvePayloadValue( getStorageProvider(), @@ -42,48 +41,41 @@ export const persistEntitiesAction: AiFlowActionActivity< * 1. Files first, because we might need to refer to them as a provenance source for other entities. * 2. Non-link entities before link entities, because we can't create a link entity without the entities it links to. */ - const entitiesWithDependenciesSortedLast = proposedEntities.toSorted( - (a, b) => { - const isAFileEntity = a.entityTypeIds.some((entityTypeId) => - fileEntityTypeIds.includes(entityTypeId), - ); - const isBFileEntity = b.entityTypeIds.some((entityTypeId) => - fileEntityTypeIds.includes(entityTypeId), - ); - if (isAFileEntity && !isBFileEntity) { - return -1; - } else if (isBFileEntity && !isAFileEntity) { - return 1; - } + const entitiesWithDependenciesSortedLast = proposedEntities.toSorted((a, b) => { + const isAFileEntity = a.entityTypeIds.some((entityTypeId) => + fileEntityTypeIds.includes(entityTypeId), + ); + const isBFileEntity = b.entityTypeIds.some((entityTypeId) => + fileEntityTypeIds.includes(entityTypeId), + ); + if (isAFileEntity && !isBFileEntity) { + return -1; + } else if (isBFileEntity && !isAFileEntity) { + return 1; + } - /** - * This assumes that there are no link entities which link to other link entities, which require being able to - * create multiple entities at once in a single transaction (since they refer to each other). - * - * @todo handle links pointing to other links via creating many entities at once, unblocked by H-1178. See also entity-result-table - */ - if ( - (a.sourceEntityId && b.sourceEntityId) || - (!a.sourceEntityId && !b.sourceEntityId) - ) { - return 0; - } + /** + * This assumes that there are no link entities which link to other link entities, which require being able to + * create multiple entities at once in a single transaction (since they refer to each other). + * + * @todo handle links pointing to other links via creating many entities at once, unblocked by H-1178. See also entity-result-table + */ + if ((a.sourceEntityId && b.sourceEntityId) || (!a.sourceEntityId && !b.sourceEntityId)) { + return 0; + } - if (a.sourceEntityId) { - return 1; - } + if (a.sourceEntityId) { + return 1; + } - return -1; - }, - ); + return -1; + }); - const persistedFilesByOriginalUrl: Record = - {}; + const persistedFilesByOriginalUrl: Record = {}; const failedEntitiesByLocalId: Record = {}; - const persistedEntitiesByLocalId: Record = - {}; + const persistedEntitiesByLocalId: Record = {}; /** * We could potentially parallelize the creation of (a) non-link entities and then (b) link entities in batches, @@ -162,9 +154,9 @@ export const persistEntitiesAction: AiFlowActionActivity< const entitySources = [ ...(entityWithResolvedLinks.provenance.sources ?? []), - ...flattenPropertyMetadata( - entityWithResolvedLinks.propertyMetadata, - ).flatMap(({ metadata }) => metadata.provenance?.sources ?? []), + ...flattenPropertyMetadata(entityWithResolvedLinks.propertyMetadata).flatMap( + ({ metadata }) => metadata.provenance?.sources ?? [], + ), ]; for (const source of entitySources) { @@ -187,8 +179,7 @@ export const persistEntitiesAction: AiFlowActionActivity< failedEntitiesByLocalId[unresolvedEntity.localEntityId] = { proposedEntity: unresolvedEntity, message: - persistedEntityOutputs.message ?? - `No outputs returned when attempting to persist entity`, + persistedEntityOutputs.message ?? `No outputs returned when attempting to persist entity`, }; continue; } diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entity-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entity-action.ts index 81f2d583a5e..2230394c971 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entity-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/persist-entity-action.ts @@ -19,18 +19,12 @@ import { StatusCode } from "@local/status"; import { getAiAssistantAccountIdActivity } from "../get-ai-assistant-account-id-activity.js"; import { extractErrorMessage } from "../infer-entities/shared/extract-validation-failure-details.js"; import { createInferredEntityNotification } from "../shared/create-inferred-entity-notification.js"; -import { - findExistingEntity, - findExistingLinkEntity, -} from "../shared/find-existing-entity.js"; +import { findExistingEntity, findExistingLinkEntity } from "../shared/find-existing-entity.js"; import { getFlowContext } from "../shared/get-flow-context.js"; import { graphApiClient } from "../shared/graph-api-client.js"; import { logProgress } from "../shared/log-progress.js"; import { createFileEntityFromUrl } from "./shared/create-file-entity-from-url.js"; -import { - getEntityUpdate, - getLatestEntityById, -} from "./shared/graph-requests.js"; +import { getEntityUpdate, getLatestEntityById } from "./shared/graph-requests.js"; import type { MatchedEntityUpdate } from "../shared/match-existing-entity.js"; import type { EntityId, VersionedUrl } from "@blockprotocol/type-system"; @@ -40,10 +34,7 @@ import type { PersistedEntityMetadata, ProposedEntityWithResolvedLinks, } from "@local/hash-isomorphic-utils/flows/types"; -import type { - HasObject, - HasSubject, -} from "@local/hash-isomorphic-utils/system-types/claim"; +import type { HasObject, HasSubject } from "@local/hash-isomorphic-utils/system-types/claim"; import type { FileProperties } from "@local/hash-isomorphic-utils/system-types/shared"; export const fileEntityTypeIds: VersionedUrl[] = [ @@ -107,23 +98,17 @@ export const persistEntity = async ({ graphApiClient, grantCreatePermissionForWeb: webId, }) - : await getWebMachineId( - { graphApi: graphApiClient }, - { actorId }, - { webId }, - ).then((maybeMachineId) => { - if (!maybeMachineId) { - throw new Error( - `Failed to get web bot account ID for web ID: ${webId}`, - ); - } - return maybeMachineId; - }); + : await getWebMachineId({ graphApi: graphApiClient }, { actorId }, { webId }).then( + (maybeMachineId) => { + if (!maybeMachineId) { + throw new Error(`Failed to get web bot account ID for web ID: ${webId}`); + } + return maybeMachineId; + }, + ); if (!webBotActorId) { - throw new Error( - `Could not get ${isAiGenerated ? "AI" : "web"} bot for web ${webId}`, - ); + throw new Error(`Could not get ${isAiGenerated ? "AI" : "web"} bot for web ${webId}`); } /** @@ -212,14 +197,12 @@ export const persistEntity = async ({ graphApiClient, { actorId: webBotActorId }, { - entityTypeIds: - stableReferenceToMatchedEntity.newValues.entityTypeIds, + entityTypeIds: stableReferenceToMatchedEntity.newValues.entityTypeIds, draft: existingEntityIsDraft ? true : createEditionAsDraft, propertyPatches: patchOperations, provenance: { ...entityValues.provenance, - sources: - stableReferenceToMatchedEntity.newValues.editionSources, + sources: stableReferenceToMatchedEntity.newValues.editionSources, }, }, ), @@ -263,9 +246,7 @@ export const persistEntity = async ({ operation, } satisfies PersistedEntityMetadata; - const createLinkFromClaimToEntity = async < - T extends "has-object" | "has-subject", - >( + const createLinkFromClaimToEntity = async ( claimId: EntityId, linkType: T, ) => { @@ -276,12 +257,9 @@ export const persistEntity = async ({ includeDrafts: draft, }); - const entityTypeId = - `https://hash.ai/@h/types/entity-type/${linkType}/v/1` as const; + const entityTypeId = `https://hash.ai/@h/types/entity-type/${linkType}/v/1` as const; - return HashLinkEntity.create< - T extends "has-subject" ? HasSubject : HasObject - >( + return HashLinkEntity.create( graphApiClient, { actorId: webBotActorId }, { @@ -310,9 +288,7 @@ export const persistEntity = async ({ ...claims.isSubjectOf.map(async (claimId) => createLinkFromClaimToEntity(claimId, "has-subject"), ), - ...claims.isObjectOf.map(async (claimId) => - createLinkFromClaimToEntity(claimId, "has-object"), - ), + ...claims.isObjectOf.map(async (claimId) => createLinkFromClaimToEntity(claimId, "has-object")), ]); logProgress([ @@ -352,9 +328,7 @@ export const persistEntity = async ({ /** * Flow action activity that persists a single entity. */ -export const persistEntityAction: AiFlowActionActivity< - "persistEntity" -> = async ({ inputs }) => { +export const persistEntityAction: AiFlowActionActivity<"persistEntity"> = async ({ inputs }) => { const { draft, proposedEntityWithResolvedLinks: proposedEntityInput } = getSimplifiedAiFlowActionInputs({ inputs, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/process-automatic-browsing-settings-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/process-automatic-browsing-settings-action.ts index 8f06fce761a..a2ac2f9ab2c 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/process-automatic-browsing-settings-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/process-automatic-browsing-settings-action.ts @@ -29,15 +29,11 @@ export const processAutomaticBrowsingSettingsAction: AiFlowActionActivity< filter: { all: [ { - equal: [ - { path: ["webId"] }, - { parameter: userAuthentication.actorId }, - ], + equal: [{ path: ["webId"] }, { parameter: userAuthentication.actorId }], }, - generateVersionedUrlMatchingFilter( - systemEntityTypes.browserPluginSettings.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.browserPluginSettings.entityTypeId, { + ignoreParents: true, + }), ], }, graphApiClient, @@ -48,16 +44,11 @@ export const processAutomaticBrowsingSettingsAction: AiFlowActionActivity< throw new Error("User has no browser plugin settings configured"); } - const automaticInferenceConfig = ( - userBrowserPluginSettings as HashEntity - ).properties[ - "https://hash.ai/@h/types/property-type/automatic-inference-configuration/" - ]; + const automaticInferenceConfig = (userBrowserPluginSettings as HashEntity) + .properties["https://hash.ai/@h/types/property-type/automatic-inference-configuration/"]; if (Object.keys(automaticInferenceConfig).length === 0) { - throw new Error( - "User has no automatic inference config set in browser plugin settings", - ); + throw new Error("User has no automatic inference config set in browser plugin settings"); } const { createAs, enabled, model, rules } = @@ -82,8 +73,7 @@ export const processAutomaticBrowsingSettingsAction: AiFlowActionActivity< restrictToDomains.length === 0 || restrictToDomains.some( (domainToMatch) => - pageHostname === domainToMatch || - pageHostname.endsWith(`.${domainToMatch}`), + pageHostname === domainToMatch || pageHostname.endsWith(`.${domainToMatch}`), ) ); }); @@ -96,9 +86,7 @@ export const processAutomaticBrowsingSettingsAction: AiFlowActionActivity< }; } - const entityTypeIdsToInfer = applicableRules.map( - ({ entityTypeId }) => entityTypeId, - ); + const entityTypeIdsToInfer = applicableRules.map(({ entityTypeId }) => entityTypeId); return { code: StatusCode.Ok, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ai.test.ts index 63988df8e2a..1b7627c60e5 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ai.test.ts @@ -1,11 +1,5 @@ import "../../shared/testing-utilities/mock-get-flow-context.js"; -import { - existsSync, - mkdirSync, - readdirSync, - readFileSync, - writeFileSync, -} from "node:fs"; +import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -44,10 +38,7 @@ export const retrievePreviousState = (params: { return JSON.parse(latestFileContent) as CoordinatingAgentState; }; -const persistState = (params: { - state: CoordinatingAgentState; - testName: string; -}) => { +const persistState = (params: { state: CoordinatingAgentState; testName: string }) => { const { state, testName } = params; const directoryPath = `${baseDirectoryPath}/${testName}`; @@ -82,8 +73,7 @@ test.skip( ], testingParams: { humanInputCanBeRequested: false, - persistState: (state) => - persistState({ state, testName: "google-subsidiaries" }), + persistState: (state) => persistState({ state, testName: "google-subsidiaries" }), resumeFromState: retrievePreviousState({ testName: "google-subsidiaries", }), @@ -120,8 +110,7 @@ test.skip( ], testingParams: { humanInputCanBeRequested: false, - persistState: (state) => - persistState({ state, testName: "sora-authors" }), + persistState: (state) => persistState({ state, testName: "sora-authors" }), resumeFromState: retrievePreviousState({ testName: "sora-authors", }), @@ -158,8 +147,7 @@ test.skip( ], testingParams: { humanInputCanBeRequested: false, - persistState: (state) => - persistState({ state, testName: "ben-werner" }), + persistState: (state) => persistState({ state, testName: "ben-werner" }), // resumeFromState: retrievePreviousState({ testName: "ben-werner" }), }, }); @@ -180,8 +168,7 @@ test.skip( inputName: "prompt", payload: { kind: "Text", - value: - 'Find information about a person called "Tim Brooks", an employee at OpenAI', + value: 'Find information about a person called "Tim Brooks", an employee at OpenAI', }, }, { @@ -194,8 +181,7 @@ test.skip( ], testingParams: { humanInputCanBeRequested: false, - persistState: (state) => - persistState({ state, testName: "tim-brooks" }), + persistState: (state) => persistState({ state, testName: "tim-brooks" }), resumeFromState: retrievePreviousState({ testName: "tim-brooks" }), }, }); @@ -223,16 +209,13 @@ test.skip( inputName: "entityTypeIds", payload: { kind: "VersionedUrl", - value: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + value: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, }, ], testingParams: { humanInputCanBeRequested: false, - persistState: (state) => - persistState({ state, testName: "openai-llm" }), + persistState: (state) => persistState({ state, testName: "openai-llm" }), resumeFromState: retrievePreviousState({ testName: "openai-llm" }), }, }); @@ -253,8 +236,7 @@ test.skip( inputName: "prompt", payload: { kind: "Text", - value: - "Find a comparison of graphics cards which can be used for running AI models", + value: "Find a comparison of graphics cards which can be used for running AI models", }, }, { @@ -267,8 +249,7 @@ test.skip( ], testingParams: { humanInputCanBeRequested: false, - persistState: (state) => - persistState({ state, testName: "graphics-cards" }), + persistState: (state) => persistState({ state, testName: "graphics-cards" }), resumeFromState: retrievePreviousState({ testName: "graphics-cards" }), }, }); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ts index d8f45c57f9a..aacb81e922a 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action.ts @@ -15,10 +15,7 @@ import { import { runCoordinatingAgent } from "./research-entities-action/coordinating-agent.js"; import type { CoordinatingAgentState } from "./research-entities-action/shared/coordinators.js"; -import type { - OriginProvenance, - ProvidedEntityEditionProvenance, -} from "@blockprotocol/type-system"; +import type { OriginProvenance, ProvidedEntityEditionProvenance } from "@blockprotocol/type-system"; import type { AiFlowActionActivity } from "@local/hash-backend-utils/flows"; /** @@ -91,10 +88,9 @@ export const researchEntitiesAction: AiFlowActionActivity< temporalAxes: currentTimeInstantTemporalAxes, filter: { all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.claim.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.claim.entityTypeId, { + ignoreParents: true, + }), { equal: [ { @@ -135,8 +131,7 @@ export const researchEntitiesAction: AiFlowActionActivity< .filter( (claim) => !state.inferredClaims.some( - (claimInState) => - claimInState.claimId === claim.metadata.recordId.entityId, + (claimInState) => claimInState.claimId === claim.metadata.recordId.entityId, ), ) .map(async (claim) => diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/checkpoints.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/checkpoints.ts index 1d2d40b67c4..463e4086924 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/checkpoints.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/checkpoints.ts @@ -10,10 +10,7 @@ import { logger } from "../../shared/activity-logger.js"; import { getTemporalClient } from "../../shared/get-flow-context.js"; import { flushLogs, logProgress } from "../../shared/log-progress.js"; -import type { - FlowSignal, - ResearchActionCheckpointState, -} from "../../../shared/signals.js"; +import type { FlowSignal, ResearchActionCheckpointState } from "../../../shared/signals.js"; import type { CoordinatingAgentState } from "./shared/coordinators.js"; /** @@ -31,9 +28,7 @@ import type { CoordinatingAgentState } from "./shared/coordinators.js"; * * This means that heartbeats (and the included details) may be recorded at a lower frequency than the interval here. */ -export const heartbeatAndWaitCancellation = async ( - state: CoordinatingAgentState, -) => { +export const heartbeatAndWaitCancellation = async (state: CoordinatingAgentState) => { const secondsBetweenHeartbeats = heartbeatTimeoutSeconds - 5; const heartbeatInterval = setInterval(() => { @@ -59,9 +54,7 @@ export const heartbeatAndWaitCancellation = async ( * – the better and more idiomatic Temporal solution is to split it up into multiple activities, * probably with the 'researchEntitiesAction' becoming a child workflow that calls activities (or its own child workflows). */ -export const createCheckpoint = async ( - checkpointData: ResearchActionCheckpointState, -) => { +export const createCheckpoint = async (checkpointData: ResearchActionCheckpointState) => { await flushLogs(); Context.current().heartbeat(checkpointData); @@ -122,22 +115,18 @@ export const getCheckpoint = async () => { } if ( - event.eventType === - proto.temporal.api.enums.v1.EventType.EVENT_TYPE_WORKFLOW_TASK_FAILED + event.eventType === proto.temporal.api.enums.v1.EventType.EVENT_TYPE_WORKFLOW_TASK_FAILED ) { if ( event.workflowTaskFailedEventAttributes?.cause === proto.temporal.api.enums.v1.WorkflowTaskFailedCause .WORKFLOW_TASK_FAILED_CAUSE_RESET_WORKFLOW ) { - checkpointId = - event.workflowTaskFailedEventAttributes.failure?.message; + checkpointId = event.workflowTaskFailedEventAttributes.failure?.message; } } } } - return Context.current().info.heartbeatDetails as - | ResearchActionCheckpointState - | undefined; + return Context.current().info.heartbeatDetails as ResearchActionCheckpointState | undefined; }; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent.ts index c136ffb4354..0c552aab496 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent.ts @@ -42,20 +42,10 @@ import type { ParsedCoordinatorToolCall, ParsedCoordinatorToolCallMap, } from "./shared/coordinator-tools.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "./shared/coordinators.js"; -import type { - EntityUuid, - OriginProvenance, - Url, -} from "@blockprotocol/type-system"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "./shared/coordinators.js"; +import type { EntityUuid, OriginProvenance, Url } from "@blockprotocol/type-system"; import type { AiFlowActionActivity } from "@local/hash-backend-utils/flows"; -import type { - ProposedEntity, - StepInput, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { ProposedEntity, StepInput } from "@local/hash-isomorphic-utils/flows/types"; import type { FileProperties } from "@local/hash-isomorphic-utils/system-types/shared"; /** @@ -117,22 +107,17 @@ const parseAndResolveCoordinatorInputs = async (params: { graphApiClient, entityTypeIds: [ ...entityTypeIds!, - ...(existingEntities?.flatMap(({ metadata }) => metadata.entityTypeIds) ?? - []), + ...(existingEntities?.flatMap(({ metadata }) => metadata.entityTypeIds) ?? []), ].filter((entityTypeId, index, all) => all.indexOf(entityTypeId) === index), actorId: userAuthentication.actorId, }); const entityTypes = Object.values(dereferencedEntityTypes) - .filter( - ({ isLink, schema }) => entityTypeIds!.includes(schema.$id) && !isLink, - ) + .filter(({ isLink, schema }) => entityTypeIds!.includes(schema.$id) && !isLink) .map(({ schema }) => schema); const linkEntityTypes = Object.values(dereferencedEntityTypes) - .filter( - ({ isLink, schema }) => entityTypeIds!.includes(schema.$id) && isLink, - ) + .filter(({ isLink, schema }) => entityTypeIds!.includes(schema.$id) && isLink) .map(({ schema }) => schema); return { @@ -175,13 +160,12 @@ export const runCoordinatingAgent: AiFlowActionActivity< testingParams, }); - const { flowEntityId, runId, stepId, webId, workflowId } = - await getFlowContext(); + const { flowEntityId, runId, stepId, webId, workflowId } = await getFlowContext(); const providedFileEntities = await getProvidedFiles(); - const providedFiles: CoordinatingAgentState["resourcesNotVisited"] = - providedFileEntities.map((entity) => { + const providedFiles: CoordinatingAgentState["resourcesNotVisited"] = providedFileEntities.map( + (entity) => { const { fileUrl: unsignedUrl, description, @@ -195,7 +179,8 @@ export const runCoordinatingAgent: AiFlowActionActivity< summary: description ?? "", fromSearchQuery: "User-provided resource", }; - }); + }, + ); if (!state.plan) { /** @@ -261,14 +246,10 @@ export const runCoordinatingAgent: AiFlowActionActivity< /** * The recursive function that processes tool calls from the coordinator until a successful 'complete' call is made. */ - const processToolCalls = async (params: { - toolCalls: ParsedCoordinatorToolCall[]; - }) => { + const processToolCalls = async (params: { toolCalls: ParsedCoordinatorToolCall[] }) => { const { toolCalls } = params; - const isTerminated = toolCalls.some( - (toolCall) => toolCall.name === "terminate", - ); + const isTerminated = toolCalls.some((toolCall) => toolCall.name === "terminate"); if (isTerminated) { return; @@ -284,9 +265,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< toolCall.name !== "waitForOutstandingTasks", ); - const completeToolCall = toolCalls.find( - (toolCall) => toolCall.name === "complete", - ); + const completeToolCall = toolCalls.find((toolCall) => toolCall.name === "complete"); const waitForTasksToolCall = toolCalls.find( (toolCall) => toolCall.name === "waitForOutstandingTasks", @@ -312,11 +291,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< ]); } - if ( - completeToolCall && - state.outstandingTasks.length > 0 && - !requestMakingToolCalls.length - ) { + if (completeToolCall && state.outstandingTasks.length > 0 && !requestMakingToolCalls.length) { /** * If the coordinator has called complete but there are still outstanding tasks, * we let them wrap up so that any claims and entities they've proposed to date are captured. @@ -360,9 +335,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< state, }); - const updatedPlan = toolCallResults.find( - (call) => !!call.updatedPlan, - )?.updatedPlan; + const updatedPlan = toolCallResults.find((call) => !!call.updatedPlan)?.updatedPlan; if (updatedPlan) { // eslint-disable-next-line no-param-reassign @@ -380,9 +353,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< } state.delegatedTasksCompleted.push( - ...toolCallResults.flatMap( - ({ delegatedTasksCompleted }) => delegatedTasksCompleted ?? [], - ), + ...toolCallResults.flatMap(({ delegatedTasksCompleted }) => delegatedTasksCompleted ?? []), ); state.suggestionsForNextStepsMade.push( @@ -394,9 +365,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< const newEntitySummaries = toolCallResults.flatMap( ({ entitySummaries }) => entitySummaries ?? [], ); - const newClaims = toolCallResults.flatMap( - ({ inferredClaims }) => inferredClaims ?? [], - ); + const newClaims = toolCallResults.flatMap(({ inferredClaims }) => inferredClaims ?? []); /** * Update the state with the new claims and entity summaries inferred from the tool calls, @@ -527,10 +496,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< return []; }); }) - .filter( - ({ url }, index, all) => - all.findIndex((file) => file.url === url) === index, - ); + .filter(({ url }, index, all) => all.findIndex((file) => file.url === url) === index); const fileEditionProvenance: ProposedEntity["provenance"] = { actorType: "ai", @@ -560,13 +526,9 @@ export const runCoordinatingAgent: AiFlowActionActivity< propertyMetadata: { value: {} }, provenance: fileEditionProvenance, entityTypeIds: [entityTypeId], - localEntityId: entityIdFromComponents( - webId, - generateUuid() as EntityUuid, - ), + localEntityId: entityIdFromComponents(webId, generateUuid() as EntityUuid), properties: { - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": - url, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": url, } satisfies FileProperties, }), ); @@ -602,10 +564,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< ]); // Store the proposed entities in S3 to avoid passing large payloads through Temporal - const allProposedEntitiesForOutput = [ - ...allProposedEntities, - ...fileEntityProposals, - ]; + const allProposedEntitiesForOutput = [...allProposedEntities, ...fileEntityProposals]; const storedRef = await storePayload({ storageProvider: getStorageProvider(), workflowId, @@ -632,9 +591,7 @@ export const runCoordinatingAgent: AiFlowActionActivity< outputName: "highlightedEntities", payload: { kind: "EntityId", - value: submittedEntities.map( - ({ localEntityId }) => localEntityId, - ), + value: submittedEntities.map(({ localEntityId }) => localEntityId), }, }, ], diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ai.test.ts index a613ca17c5c..af830f3898b 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ai.test.ts @@ -10,90 +10,79 @@ test.skip( "Test checkDelegatedTasksAgent", async () => { const { userAuthentication } = await getFlowContext(); - const allDereferencedEntityTypesById = - await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/graphics-card/v/1", - ], - graphApiClient, - actorId: userAuthentication.actorId, - }); + const allDereferencedEntityTypesById = await getDereferencedEntityTypesActivity({ + entityTypeIds: ["https://hash.ai/@h/types/entity-type/graphics-card/v/1"], + graphApiClient, + actorId: userAuthentication.actorId, + }); - const { rejectedDelegatedTasks, acceptedDelegatedTasks } = - await checkDelegatedTasksAgent({ - input: { - humanInputCanBeRequested: false, - prompt: - "Find the best 3 consumer graphics cards for running AI models.", - allDereferencedEntityTypesById, - entityTypes: Object.values(allDereferencedEntityTypesById) - .filter(({ isLink }) => !isLink) - .map(({ schema }) => schema), - linkEntityTypes: Object.values(allDereferencedEntityTypesById) - .filter(({ isLink }) => isLink) - .map(({ schema }) => schema), + const { rejectedDelegatedTasks, acceptedDelegatedTasks } = await checkDelegatedTasksAgent({ + input: { + humanInputCanBeRequested: false, + prompt: "Find the best 3 consumer graphics cards for running AI models.", + allDereferencedEntityTypesById, + entityTypes: Object.values(allDereferencedEntityTypesById) + .filter(({ isLink }) => !isLink) + .map(({ schema }) => schema), + linkEntityTypes: Object.values(allDereferencedEntityTypesById) + .filter(({ isLink }) => isLink) + .map(({ schema }) => schema), + }, + state: { + coordinatorIdentifiers: { + workerInstanceId: "1", + parentInstanceId: null, + workerType: "Coordinator", + toolCallId: null, }, - state: { - coordinatorIdentifiers: { - workerInstanceId: "1", - parentInstanceId: null, - workerType: "Coordinator", - toolCallId: null, - }, - entitySummaries: [], - hasConductedCompleteCheckStep: false, - inferredClaims: [], - plan: "", - lastCompletedToolCalls: [], - proposedEntities: [], - questionsAndAnswers: "", - submittedEntityIds: [], - delegatedTasksCompleted: [], - outstandingTasks: [], - suggestionsForNextStepsMade: [], - resourcesNotVisited: [], - resourceUrlsVisited: [], - webQueriesMade: [], - workersStarted: [], + entitySummaries: [], + hasConductedCompleteCheckStep: false, + inferredClaims: [], + plan: "", + lastCompletedToolCalls: [], + proposedEntities: [], + questionsAndAnswers: "", + submittedEntityIds: [], + delegatedTasksCompleted: [], + outstandingTasks: [], + suggestionsForNextStepsMade: [], + resourcesNotVisited: [], + resourceUrlsVisited: [], + webQueriesMade: [], + workersStarted: [], + }, + delegatedTasks: [ + { + delegatedTaskId: "1", + goal: "Find the technical specifications of the top 3 consumer graphics cards for running AI models, including memory size, memory type, number of CUDA cores, number of Tensor cores, base clock speed, boost clock speed, power draw, length and width.", + explanation: + "To recommend the best graphics cards for running AI models, we need to gather detailed technical specifications on the top contenders. This will allow us to compare their capabilities and suitability for AI workloads. The memory size, memory type, number of CUDA/Tensor cores, clock speeds, power draw and dimensions are all important factors that will impact AI performance and compatibility. The results will be used to populate the Name, Description, Memory Size, Memory Type, NVIDIA CUDA Cores, Tensor Cores, Base Clock, Boost Clock, Power Draw, Length and Width properties on the Graphics Card entity type for the top 3 candidates.", }, - delegatedTasks: [ - { - delegatedTaskId: "1", - goal: "Find the technical specifications of the top 3 consumer graphics cards for running AI models, including memory size, memory type, number of CUDA cores, number of Tensor cores, base clock speed, boost clock speed, power draw, length and width.", - explanation: - "To recommend the best graphics cards for running AI models, we need to gather detailed technical specifications on the top contenders. This will allow us to compare their capabilities and suitability for AI workloads. The memory size, memory type, number of CUDA/Tensor cores, clock speeds, power draw and dimensions are all important factors that will impact AI performance and compatibility. The results will be used to populate the Name, Description, Memory Size, Memory Type, NVIDIA CUDA Cores, Tensor Cores, Base Clock, Boost Clock, Power Draw, Length and Width properties on the Graphics Card entity type for the top 3 candidates.", - }, - { - delegatedTaskId: "2", - goal: "Gather expert reviews and benchmark results comparing the AI performance of the top 3 consumer graphics cards.", - explanation: - "In addition to raw specs, real-world performance benchmarks and expert opinions from trusted review sites will help identify which cards offer the best performance, value and user experience for AI/ML workloads. This information can be incorporated into the Description property on the Graphics Card entities to provide additional context beyond just technical specifications.", - }, - ], - // delegatedTasks: [ - // { - // delegatedTaskId: "1", - // goal: "Find information about the NVIDIA GeForce RTX 3080 graphics card.", - // explanation: - // "The NVIDIA GeForce RTX 3080 is a high-end consumer graphics card that is known for its excellent performance in gaming and AI workloads. We need to find detailed technical specifications, expert reviews, and benchmark results to provide a comprehensive overview of the card's capabilities.", - // }, - // { - // delegatedTaskId: "2", - // goal: "Find the memory of the NVIDIA GeForce RTX 3080 graphics card.", - // explanation: - // "The memory of the NVIDIA GeForce RTX 3080 is an important factor that influences its performance in AI workloads. We need to find information about the memory size, memory type, and memory bandwidth of the card to provide a detailed description of its capabilities.", - // }, - // ], - }); + { + delegatedTaskId: "2", + goal: "Gather expert reviews and benchmark results comparing the AI performance of the top 3 consumer graphics cards.", + explanation: + "In addition to raw specs, real-world performance benchmarks and expert opinions from trusted review sites will help identify which cards offer the best performance, value and user experience for AI/ML workloads. This information can be incorporated into the Description property on the Graphics Card entities to provide additional context beyond just technical specifications.", + }, + ], + // delegatedTasks: [ + // { + // delegatedTaskId: "1", + // goal: "Find information about the NVIDIA GeForce RTX 3080 graphics card.", + // explanation: + // "The NVIDIA GeForce RTX 3080 is a high-end consumer graphics card that is known for its excellent performance in gaming and AI workloads. We need to find detailed technical specifications, expert reviews, and benchmark results to provide a comprehensive overview of the card's capabilities.", + // }, + // { + // delegatedTaskId: "2", + // goal: "Find the memory of the NVIDIA GeForce RTX 3080 graphics card.", + // explanation: + // "The memory of the NVIDIA GeForce RTX 3080 is an important factor that influences its performance in AI workloads. We need to find information about the memory size, memory type, and memory bandwidth of the card to provide a detailed description of its capabilities.", + // }, + // ], + }); // eslint-disable-next-line no-console - console.log( - JSON.stringify( - { rejectedDelegatedTasks, acceptedDelegatedTasks }, - null, - 2, - ), - ); + console.log(JSON.stringify({ rejectedDelegatedTasks, acceptedDelegatedTasks }, null, 2)); expect(rejectedDelegatedTasks).toBeDefined(); }, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ts index f2f577ecc44..6e407e359d1 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/check-delegated-tasks-agent.ts @@ -7,10 +7,7 @@ import { graphApiClient } from "../../../shared/graph-api-client.js"; import { simplifyEntityTypeForLlmConsumption } from "../shared/simplify-for-llm-consumption.js"; import type { LlmToolDefinition } from "../../../shared/get-llm-response/types.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "../shared/coordinators.js"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "../shared/coordinators.js"; import type { JSONSchemaDefinition } from "openai/lib/jsonschema"; type SubmitVerdictToolCallInput = { @@ -62,9 +59,7 @@ export const checkDelegatedTasksAgent = async (params: { * * @see https://linear.app/hash/issue/H-2826/simplify-property-values-for-llm-consumption */ - input.linkEntityTypes - ? `Link Types: ${JSON.stringify(input.linkEntityTypes)}` - : "" + input.linkEntityTypes ? `Link Types: ${JSON.stringify(input.linkEntityTypes)}` : "" } Pay careful attention to the properties of the entities and links when @@ -94,13 +89,11 @@ export const checkDelegatedTasksAgent = async (params: { don't name and specify which entities to focus on. Otherwise each delegated task may look up information about different entities. `; - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const submitVerdictToolDefinition: LlmToolDefinition<"submitVerdict"> = { name: "submitVerdict", - description: - "Submit the verdict of which delegatedTasks to accept or reject", + description: "Submit the verdict of which delegatedTasks to accept or reject", inputSchema: { additionalProperties: false, type: "object", @@ -117,8 +110,7 @@ export const checkDelegatedTasksAgent = async (params: { }, reason: { type: "string", - description: - "The reason for accepting or rejecting the delegated task", + description: "The reason for accepting or rejecting the delegated task", }, }, required: ["reason", "accept"], @@ -126,9 +118,7 @@ export const checkDelegatedTasksAgent = async (params: { }), {} as Record, ), - required: [ - ...delegatedTasks.map(({ delegatedTaskId }) => delegatedTaskId), - ], + required: [...delegatedTasks.map(({ delegatedTaskId }) => delegatedTaskId)], }, }; @@ -174,8 +164,7 @@ export const checkDelegatedTasksAgent = async (params: { throw new Error("No tool call found in the LLM response"); } - const submitVerdictToolCallInput = - toolCall.input as SubmitVerdictToolCallInput; + const submitVerdictToolCallInput = toolCall.input as SubmitVerdictToolCallInput; const acceptedDelegatedTasks: { delegatedTaskId: string; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/create-initial-plan.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/create-initial-plan.ts index 2c96ef4288a..709fe2c5beb 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/create-initial-plan.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/create-initial-plan.ts @@ -12,19 +12,10 @@ import { generateToolDefinitions, } from "../shared/coordinator-tools.js"; import { coordinatingAgentModel } from "../shared/coordinators.js"; -import { - generateInitialUserMessage, - generateSystemPromptPrefix, -} from "./generate-messages.js"; - -import type { - LlmMessage, - LlmUserMessage, -} from "../../../shared/get-llm-response/llm-message.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "../shared/coordinators.js"; +import { generateInitialUserMessage, generateSystemPromptPrefix } from "./generate-messages.js"; + +import type { LlmMessage, LlmUserMessage } from "../../../shared/get-llm-response/llm-message.js"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "../shared/coordinators.js"; const maximumRetries = 3; @@ -35,11 +26,9 @@ export const createInitialPlan = async (params: { providedFiles: CoordinatingAgentState["resourcesNotVisited"]; retryContext?: { retryMessages: LlmMessage[]; retryCount: number }; }): Promise> => { - const { input, state, questionsAndAnswers, providedFiles, retryContext } = - params; + const { input, state, questionsAndAnswers, providedFiles, retryContext } = params; - const { dataSources, userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { dataSources, userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const systemPrompt = dedent(` ${generateSystemPromptPrefix({ input })} @@ -49,10 +38,7 @@ export const createInitialPlan = async (params: { ? dedent(` The user has provided you with the following resources which can be used to infer claims from: ${providedFiles - .map( - (file) => - `Url: ${file.url}\nTitle: ${file.title}`, - ) + .map((file) => `Url: ${file.url}\nTitle: ${file.title}`) .join("\n\n")}`) : "" } @@ -135,22 +121,17 @@ export const createInitialPlan = async (params: { ); if (llmResponse.status !== "ok") { - throw new Error( - `Failed to get LLM response: ${JSON.stringify(llmResponse)}`, - ); + throw new Error(`Failed to get LLM response: ${JSON.stringify(llmResponse)}`); } const { message } = llmResponse; const toolCalls = getToolCallsFromLlmAssistantMessage({ message }); - const updatePlanToolCall = toolCalls.find( - (toolCall) => toolCall.name === "updatePlan", - ); + const updatePlanToolCall = toolCalls.find((toolCall) => toolCall.name === "updatePlan"); if (updatePlanToolCall) { - const { plan } = - updatePlanToolCall.input as CoordinatorToolCallArguments["updatePlan"]; + const { plan } = updatePlanToolCall.input as CoordinatorToolCallArguments["updatePlan"]; return { plan, questionsAndAnswers }; } @@ -165,9 +146,7 @@ export const createInitialPlan = async (params: { } logger.debug( - `Retrying to create initial plan with retry message: ${stringify( - retryParams.retryMessage, - )}`, + `Retrying to create initial plan with retry message: ${stringify(retryParams.retryMessage)}`, ); return createInitialPlan({ @@ -210,9 +189,7 @@ export const createInitialPlan = async (params: { { type: "text", text: `You didn't make any tool calls, you must call the ${ - input.humanInputCanBeRequested - ? `"requestHumanInput" tool or the` - : "" + input.humanInputCanBeRequested ? `"requestHumanInput" tool or the` : "" }"updatePlan" tool.`, }, ], @@ -227,9 +204,7 @@ export const createInitialPlan = async (params: { type: "tool_result", tool_use_id: id, content: `You cannot call the "${name}" tool yet, you must call the ${ - input.humanInputCanBeRequested - ? `"requestHumanInput" tool or the` - : "" + input.humanInputCanBeRequested ? `"requestHumanInput" tool or the` : "" }"updatePlan" tool first.`, is_error: true, })), diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/generate-messages.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/generate-messages.ts index 26511754a8f..6ff207eeec7 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/generate-messages.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/generate-messages.ts @@ -7,10 +7,7 @@ import { } from "../shared/simplify-for-llm-consumption.js"; import type { LlmMessageTextContent } from "../../../shared/get-llm-response/llm-message.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "../shared/coordinators.js"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "../shared/coordinators.js"; export const generateProgressReport = (params: { input: CoordinatingAgentInput; @@ -160,11 +157,8 @@ export const generateProgressReport = (params: { }; }; -export const generateSystemPromptPrefix = (params: { - input: CoordinatingAgentInput; -}) => { - const { linkEntityTypes, existingEntities, reportSpecification } = - params.input; +export const generateSystemPromptPrefix = (params: { input: CoordinatingAgentInput }) => { + const { linkEntityTypes, existingEntities, reportSpecification } = params.input; return dedent(` You are a coordinating agent for a research task. The date is ${new Date().toUTCString()}. @@ -227,27 +221,16 @@ export const generateInitialUserMessage = (params: { input: CoordinatingAgentInput; questionsAndAnswers: CoordinatingAgentState["questionsAndAnswers"]; }): LlmMessageTextContent => { - const { - prompt, - reportSpecification, - entityTypes, - linkEntityTypes, - existingEntities, - } = params.input; + const { prompt, reportSpecification, entityTypes, linkEntityTypes, existingEntities } = + params.input; return { type: "text", text: dedent(` ${prompt} -${ - reportSpecification - ? `${reportSpecification}` - : "" -} +${reportSpecification ? `${reportSpecification}` : ""} -${entityTypes - .map((entityType) => simplifyEntityTypeForLlmConsumption({ entityType })) - .join("\n")} +${entityTypes.map((entityType) => simplifyEntityTypeForLlmConsumption({ entityType })).join("\n")} ${ /** @@ -258,17 +241,11 @@ ${ */ linkEntityTypes ? `${linkEntityTypes - .map((linkType) => - simplifyEntityTypeForLlmConsumption({ entityType: linkType }), - ) + .map((linkType) => simplifyEntityTypeForLlmConsumption({ entityType: linkType })) .join("\n")}` : "" } -${ - existingEntities - ? `Existing Entities: ${JSON.stringify(existingEntities)}` - : "" -} +${existingEntities ? `Existing Entities: ${JSON.stringify(existingEntities)}` : ""} `), }; }; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/process-complete-tool-call.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/process-complete-tool-call.ts index 2c39b8cdcf7..42355b07cc2 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/process-complete-tool-call.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/process-complete-tool-call.ts @@ -4,10 +4,7 @@ import { logger } from "../../../shared/activity-logger.js"; import type { ParsedLlmToolCall } from "../../../shared/get-llm-response/types.js"; import type { ParsedCoordinatorToolCallMap } from "../shared/coordinator-tools.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "../shared/coordinators.js"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "../shared/coordinators.js"; /** * Processes a 'complete' call from the coordinating agent. @@ -49,10 +46,7 @@ export const processCompleteToolCall = ({ const { entityIds } = toolCall.input; const invalidEntityIds = entityIds.filter( - (entityId) => - !state.proposedEntities.some( - ({ localEntityId }) => localEntityId === entityId, - ), + (entityId) => !state.proposedEntities.some(({ localEntityId }) => localEntityId === entityId), ); if (invalidEntityIds.length > 0) { @@ -66,9 +60,7 @@ export const processCompleteToolCall = ({ ${ state.proposedEntities.length > 0 ? `Valid entity IDs are: ${JSON.stringify( - state.proposedEntities.map( - ({ localEntityId }) => localEntityId, - ), + state.proposedEntities.map(({ localEntityId }) => localEntityId), )}` : `You haven't discovered any entities yet.` } @@ -85,10 +77,7 @@ export const processCompleteToolCall = ({ ); const missingEntityTypes = input.entityTypes.filter( - ({ $id }) => - !submittedEntities.some(({ entityTypeIds }) => - entityTypeIds.includes($id), - ), + ({ $id }) => !submittedEntities.some(({ entityTypeIds }) => entityTypeIds.includes($id)), ); if (missingEntityTypes.length > 0) { @@ -100,10 +89,7 @@ export const processCompleteToolCall = ({ } const missingLinkEntityTypes = input.linkEntityTypes?.filter( - ({ $id }) => - !submittedEntities.some(({ entityTypeIds }) => - entityTypeIds.includes($id), - ), + ({ $id }) => !submittedEntities.some(({ entityTypeIds }) => entityTypeIds.includes($id)), ); if (missingLinkEntityTypes && missingLinkEntityTypes.length > 0) { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/request-coordinator-actions.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/request-coordinator-actions.ts index ebfa1dfe814..4f440dc994a 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/request-coordinator-actions.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/request-coordinator-actions.ts @@ -15,10 +15,7 @@ import { import type { LlmMessage } from "../../../shared/get-llm-response/llm-message.js"; import type { ParsedCoordinatorToolCall } from "../shared/coordinator-tools.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "../shared/coordinators.js"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "../shared/coordinators.js"; /** * Given the current state of the coordinating agent, request the next actions to be taken. @@ -39,20 +36,17 @@ export const requestCoordinatorActions = async (params: { Make as many tool calls as are required to progress towards completing the task. `); - const llmMessagesFromPreviousToolCalls = - mapPreviousCoordinatorCallsToLlmMessages({ - includeErrorsOnly: true, - previousCalls: state.lastCompletedToolCalls, - }); + const llmMessagesFromPreviousToolCalls = mapPreviousCoordinatorCallsToLlmMessages({ + includeErrorsOnly: true, + previousCalls: state.lastCompletedToolCalls, + }); const initialUserMessage = generateInitialUserMessage({ input, questionsAndAnswers: state.questionsAndAnswers, }); - const messages: LlmMessage[] = [ - { role: "user", content: [initialUserMessage] }, - ]; + const messages: LlmMessage[] = [{ role: "user", content: [initialUserMessage] }]; messages.push(...llmMessagesFromPreviousToolCalls); @@ -63,16 +57,13 @@ export const requestCoordinatorActions = async (params: { content: [progressReport], }); - const { dataSources, userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { dataSources, userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const tools = Object.values( generateToolDefinitions({ dataSources, omitTools: [ - ...(input.humanInputCanBeRequested - ? [] - : ["requestHumanInput" as const]), + ...(input.humanInputCanBeRequested ? [] : ["requestHumanInput" as const]), ...(state.proposedEntities.length > 0 ? [] : ["complete" as const]), ], state, @@ -100,9 +91,7 @@ export const requestCoordinatorActions = async (params: { ); if (llmResponse.status !== "ok") { - throw new Error( - `Failed to get LLM response: ${JSON.stringify(llmResponse)}`, - ); + throw new Error(`Failed to get LLM response: ${JSON.stringify(llmResponse)}`); } const { message } = llmResponse; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ai.test.ts index 1437772fc0f..e59d0fa466d 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ai.test.ts @@ -21,10 +21,9 @@ test.skip( { filter: { all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.user.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.user.entityTypeId, { + ignoreParents: true, + }), ], }, temporalAxes: currentTimeInstantTemporalAxes, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ts index 1f290a9dcc0..e9a215c0b44 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/summarize-existing-entities.ts @@ -28,9 +28,7 @@ const systemPrompt = dedent(` const toolName = "submitEntitySummaries"; -const registerEntitySummariesToolDefinition: LlmToolDefinition< - typeof toolName -> = { +const registerEntitySummariesToolDefinition: LlmToolDefinition = { name: toolName, description: "Register entity summaries", inputSchema: { @@ -75,8 +73,7 @@ export const summarizeExistingEntities = async (params: { }): Promise<{ existingEntitySummaries: ExistingEntitySummary[] }> => { const { existingEntities } = params; - const { flowEntityId, userAuthentication, stepId, webId } = - await getFlowContext(); + const { flowEntityId, userAuthentication, stepId, webId } = await getFlowContext(); const llmResponse = await getLlmResponse( { @@ -89,9 +86,7 @@ export const summarizeExistingEntities = async (params: { content: [ { type: "text", - text: `Entities: ${JSON.stringify( - existingEntities.map(simplifyEntity), - )}`, + text: `Entities: ${JSON.stringify(existingEntities.map(simplifyEntity))}`, }, ], }, @@ -111,9 +106,7 @@ export const summarizeExistingEntities = async (params: { ); if (llmResponse.status !== "ok") { - throw new Error( - `Failed to get LLM response: ${JSON.stringify(llmResponse)}`, - ); + throw new Error(`Failed to get LLM response: ${JSON.stringify(llmResponse)}`); } const { message } = llmResponse; @@ -135,9 +128,7 @@ export const summarizeExistingEntities = async (params: { if (!existingEntity) { /** @todo: add retry logic */ - throw new Error( - `Entity with entityId ${entityId} not found in the existing entities.`, - ); + throw new Error(`Entity with entityId ${entityId} not found in the existing entities.`); } validEntitySummaries.push({ diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/update-state-from-inferred-claims.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/update-state-from-inferred-claims.ts index 48c8484ea7d..1cebc8b4ac7 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/update-state-from-inferred-claims.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/coordinating-agent/update-state-from-inferred-claims.ts @@ -2,17 +2,11 @@ import { isNotNullish } from "@local/hash-isomorphic-utils/types"; import { proposeEntitiesFromClaims } from "../../shared/propose-entities-from-claims.js"; import { deduplicateClaims } from "../shared/deduplicate-claims.js"; -import { - deduplicateEntities, - type DuplicateReport, -} from "../shared/deduplicate-entities.js"; +import { deduplicateEntities, type DuplicateReport } from "../shared/deduplicate-entities.js"; import type { Claim } from "../../shared/claims.js"; import type { LocalEntitySummary } from "../../shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "../shared/coordinators.js"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "../shared/coordinators.js"; import type { EntityId } from "@blockprotocol/type-system"; import type { WorkerIdentifiers } from "@local/hash-isomorphic-utils/flows/types"; @@ -22,35 +16,31 @@ const adjustDuplicates = (params: { }) => { const { duplicates, entityIdsWhichCannotBeDeduplicated } = params; - const adjustedDuplicates = duplicates.map( - ({ canonicalId, duplicateIds }) => { - if (entityIdsWhichCannotBeDeduplicated.includes(canonicalId)) { - return { canonicalId, duplicateIds }; - } - - const existingEntityIdMarkedAsDuplicate = duplicateIds.find((id) => - entityIdsWhichCannotBeDeduplicated.includes(id), - ); + const adjustedDuplicates = duplicates.map(({ canonicalId, duplicateIds }) => { + if (entityIdsWhichCannotBeDeduplicated.includes(canonicalId)) { + return { canonicalId, duplicateIds }; + } - /** - * @todo: this doesn't account for when there are duplicates - * detected in the existing entities. - */ - if (existingEntityIdMarkedAsDuplicate) { - return { - canonicalId: existingEntityIdMarkedAsDuplicate, - duplicateIds: [ - ...duplicateIds.filter( - (id) => id !== existingEntityIdMarkedAsDuplicate, - ), - canonicalId, - ], - }; - } + const existingEntityIdMarkedAsDuplicate = duplicateIds.find((id) => + entityIdsWhichCannotBeDeduplicated.includes(id), + ); - return { canonicalId, duplicateIds }; - }, - ); + /** + * @todo: this doesn't account for when there are duplicates + * detected in the existing entities. + */ + if (existingEntityIdMarkedAsDuplicate) { + return { + canonicalId: existingEntityIdMarkedAsDuplicate, + duplicateIds: [ + ...duplicateIds.filter((id) => id !== existingEntityIdMarkedAsDuplicate), + canonicalId, + ], + }; + } + + return { canonicalId, duplicateIds }; + }); return adjustedDuplicates; }; @@ -69,8 +59,7 @@ export const updateStateFromInferredClaims = async (params: { newEntitySummaries: LocalEntitySummary[]; workerIdentifiers: WorkerIdentifiers; }) => { - const { input, state, newEntitySummaries, newClaims, workerIdentifiers } = - params; + const { input, state, newEntitySummaries, newClaims, workerIdentifiers } = params; /** * Step 1: Deduplicate entities (if necessary) @@ -112,35 +101,25 @@ export const updateStateFromInferredClaims = async (params: { ...adjustedDuplicates.map(({ canonicalId }) => canonicalId), ); - state.inferredClaims = [...state.inferredClaims, ...newClaims].map( - (claim) => { - const { subjectEntityLocalId, objectEntityLocalId } = claim; - const subjectDuplicate = adjustedDuplicates.find(({ duplicateIds }) => - duplicateIds.includes(subjectEntityLocalId), - ); + state.inferredClaims = [...state.inferredClaims, ...newClaims].map((claim) => { + const { subjectEntityLocalId, objectEntityLocalId } = claim; + const subjectDuplicate = adjustedDuplicates.find(({ duplicateIds }) => + duplicateIds.includes(subjectEntityLocalId), + ); - const objectDuplicate = objectEntityLocalId - ? duplicates.find(({ duplicateIds }) => - duplicateIds.includes(objectEntityLocalId), - ) - : undefined; + const objectDuplicate = objectEntityLocalId + ? duplicates.find(({ duplicateIds }) => duplicateIds.includes(objectEntityLocalId)) + : undefined; - return { - ...claim, - subjectEntityLocalId: - subjectDuplicate?.canonicalId ?? claim.subjectEntityLocalId, - objectEntityLocalId: - objectDuplicate?.canonicalId ?? objectEntityLocalId, - }; - }, - ); + return { + ...claim, + subjectEntityLocalId: subjectDuplicate?.canonicalId ?? claim.subjectEntityLocalId, + objectEntityLocalId: objectDuplicate?.canonicalId ?? objectEntityLocalId, + }; + }); - state.entitySummaries = [ - ...state.entitySummaries, - ...newEntitySummaries, - ].filter( - ({ localId }) => - !duplicates.some(({ duplicateIds }) => duplicateIds.includes(localId)), + state.entitySummaries = [...state.entitySummaries, ...newEntitySummaries].filter( + ({ localId }) => !duplicates.some(({ duplicateIds }) => duplicateIds.includes(localId)), ); /** @@ -208,24 +187,20 @@ export const updateStateFromInferredClaims = async (params: { /** * Given the affected entities, we also need the summaries of entities they may link to. */ - const potentialLinkTargetEntitySummaries = state.entitySummaries.filter( - ({ localId }) => - relevantClaims.some( - ({ objectEntityLocalId }) => localId === objectEntityLocalId, - ), + const potentialLinkTargetEntitySummaries = state.entitySummaries.filter(({ localId }) => + relevantClaims.some(({ objectEntityLocalId }) => localId === objectEntityLocalId), ); if (relevantClaims.length) { - const { proposedEntities: newProposedEntities } = - await proposeEntitiesFromClaims({ - dereferencedEntityTypes: input.allDereferencedEntityTypesById, - entitySummaries, - existingEntitySummaries: input.existingEntitySummaries, - existingProposals: state.proposedEntities, - claims: relevantClaims, - potentialLinkTargetEntitySummaries, - workerIdentifiers, - }); + const { proposedEntities: newProposedEntities } = await proposeEntitiesFromClaims({ + dereferencedEntityTypes: input.allDereferencedEntityTypesById, + entitySummaries, + existingEntitySummaries: input.existingEntitySummaries, + existingProposals: state.proposedEntities, + claims: relevantClaims, + potentialLinkTargetEntitySummaries, + workerIdentifiers, + }); /** * Step 4. Update the state with the new and updated proposals diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/get-answers-from-human.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/get-answers-from-human.ts index 0323a6944c4..2346c8217b8 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/get-answers-from-human.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/get-answers-from-human.ts @@ -3,9 +3,7 @@ import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; import { getFlowContext } from "../../shared/get-flow-context.js"; import { requestExternalInput } from "../../shared/request-external-input.js"; -export const getAnswersFromHuman = async ( - questions: string[], -): Promise => { +export const getAnswersFromHuman = async (questions: string[]): Promise => { const { stepId } = await getFlowContext(); const { @@ -20,9 +18,7 @@ export const getAnswersFromHuman = async ( }); const responseString = answers - .map( - (answer, index) => `\nQuestion: ${questions[index]}\nAnswer: ${answer}\n`, - ) + .map((answer, index) => `\nQuestion: ${questions[index]}\nAnswer: ${answer}\n`) .join("\n"); return responseString; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ai.test.ts index 774f14cc619..f8a178d224e 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ai.test.ts @@ -22,15 +22,12 @@ test.skip( const status = await linkFollowerAgent({ input: { goal: "Obtain the full list of current members of Church Lab", - entityTypes: Object.values(dereferencedEntityTypes).map( - ({ schema }) => schema, - ), + entityTypes: Object.values(dereferencedEntityTypes).map(({ schema }) => schema), existingEntitiesOfInterest: [], initialResource: { url: "https://churchlab.hms.harvard.edu/index.php/lab-members#current" as Url, exampleOfExpectedContent: "Current Members: ...", - descriptionOfExpectedContent: - "The current members of the lab are listed on the page.", + descriptionOfExpectedContent: "The current members of the lab are listed on the page.", reason: "The page should include the current members of the lab.", goal: "Obtain the full list of current members of Church Lab", }, @@ -67,9 +64,7 @@ test.skip( const status = await linkFollowerAgent({ input: { goal: 'Obtain the full list of authors of the Sora article titled "Video Generation Models as World Simulators"', - entityTypes: Object.values(dereferencedEntityTypes).map( - ({ schema }) => schema, - ), + entityTypes: Object.values(dereferencedEntityTypes).map(({ schema }) => schema), existingEntitiesOfInterest: [], initialResource: { url: "https://openai.com/index/video-generation-models-as-world-simulators/" as Url, @@ -104,9 +99,7 @@ test.skip( const { userAuthentication } = await getFlowContext(); const dereferencedEntityTypes = await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], actorId: userAuthentication.actorId, graphApiClient, }); @@ -114,16 +107,13 @@ test.skip( const status = await linkFollowerAgent({ input: { goal: "Get all the stock market constituents of the FTSE350.", - entityTypes: Object.values(dereferencedEntityTypes).map( - ({ schema }) => schema, - ), + entityTypes: Object.values(dereferencedEntityTypes).map(({ schema }) => schema), existingEntitiesOfInterest: [], initialResource: { url: "https://www.londonstockexchange.com/indices/ftse-350/constituents/table" as Url, goal: "Get all the stock market constituents of the FTSE350.", exampleOfExpectedContent: "Constituents: ...", - descriptionOfExpectedContent: - "The constituents of the FTSE350 are listed on the page.", + descriptionOfExpectedContent: "The constituents of the FTSE350 are listed on the page.", reason: "The page should include the constituents of the FTSE350.", }, }, @@ -159,9 +149,7 @@ test.skip( const status = await linkFollowerAgent({ input: { goal: "Identify the top 3 graphics cards suitable for AI model processing, including their specifications and features.", - entityTypes: Object.values(dereferencedEntityTypes).map( - ({ schema }) => schema, - ), + entityTypes: Object.values(dereferencedEntityTypes).map(({ schema }) => schema), existingEntitiesOfInterest: [], initialResource: { goal: "Identify the top 3 graphics cards suitable for AI model processing, including their specifications and features.", @@ -169,8 +157,7 @@ test.skip( exampleOfExpectedContent: "Graphics Cards: ...", descriptionOfExpectedContent: "The top 3 graphics cards for AI model processing are listed on the page.", - reason: - "The page should include the top 3 graphics cards for AI model processing.", + reason: "The page should include the top 3 graphics cards for AI model processing.", }, }, workerIdentifiers: { @@ -197,9 +184,7 @@ test.skip( const { userAuthentication } = await getFlowContext(); const dereferencedEntityTypes = await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/investment-fund/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/investment-fund/v/1"], actorId: userAuthentication.actorId, graphApiClient, }); @@ -207,9 +192,7 @@ test.skip( const status = await linkFollowerAgent({ input: { goal: "Get the list of investors of Marks and Spencer's, based on the 2023 annual investors report PDF file.", - entityTypes: Object.values(dereferencedEntityTypes).map( - ({ schema }) => schema, - ), + entityTypes: Object.values(dereferencedEntityTypes).map(({ schema }) => schema), existingEntitiesOfInterest: [], initialResource: { url: "https://corporate.marksandspencer.com/investors" as Url, @@ -217,8 +200,7 @@ test.skip( exampleOfExpectedContent: "Investors: ...", descriptionOfExpectedContent: "The investors of Marks and Spencer's are listed on the page.", - reason: - "The page should include the investors of Marks and Spencer's.", + reason: "The page should include the investors of Marks and Spencer's.", }, }, workerIdentifiers: { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ts index 48bb5a423a3..0c14911d0b8 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent.ts @@ -7,10 +7,7 @@ import { getStorageProvider } from "@local/hash-backend-utils/flows/payload-stor import { getWebPageActivity } from "../../get-web-page-activity.js"; import { logger } from "../../shared/activity-logger.js"; -import { - getFlowContext, - getProvidedFileByUrl, -} from "../../shared/get-flow-context.js"; +import { getFlowContext, getProvidedFileByUrl } from "../../shared/get-flow-context.js"; import { logProgress } from "../../shared/log-progress.js"; import { stringify } from "../../shared/stringify.js"; import { inferSummariesThenClaimsFromText } from "../shared/infer-summaries-then-claims-from-text.js"; @@ -88,9 +85,7 @@ const isContentAtUrlPdfFile = async (params: { url: string }) => { } } catch (error) { logger.error( - `Error encountered when checking if content at URL ${url} is a PDF file: ${stringify( - error, - )}`, + `Error encountered when checking if content at URL ${url} is a PDF file: ${stringify(error)}`, ); } return false; @@ -141,9 +136,7 @@ const exploreResource = async (params: { * and otherwise use the proxy URL stored on the entity itself in logs and provenance records. */ const storageKey = - hashEntityForFile.properties[ - "https://hash.ai/@h/types/property-type/file-storage-key/" - ]; + hashEntityForFile.properties["https://hash.ai/@h/types/property-type/file-storage-key/"]; if (storageKey) { urlForDownload = await getStorageProvider().presignDownload({ @@ -156,8 +149,7 @@ const exploreResource = async (params: { return { status: "not-explored", resource, - reason: - "Public internet access is disabled – you provided a URL to the public web.", + reason: "Public internet access is disabled – you provided a URL to the public web.", }; } @@ -217,9 +209,7 @@ const exploreResource = async (params: { query, }); - const textChunks = sourceNodes?.map(({ node }) => - node.getContent(MetadataMode.NONE), - ); + const textChunks = sourceNodes?.map(({ node }) => node.getContent(MetadataMode.NONE)); if (!textChunks || textChunks.length === 0) { return { @@ -229,18 +219,13 @@ const exploreResource = async (params: { }; } - logger.debug( - `Vector DB query returned ${textChunks.length} chunks: ${stringify( - textChunks, - )}`, - ); + logger.debug(`Vector DB query returned ${textChunks.length} chunks: ${stringify(textChunks)}`); - const filteredAndRankedTextChunksResponse = - await filterAndRankTextChunksAgent({ - description: resource.descriptionOfExpectedContent, - exampleText: resource.exampleOfExpectedContent, - textChunks, - }); + const filteredAndRankedTextChunksResponse = await filterAndRankTextChunksAgent({ + description: resource.descriptionOfExpectedContent, + exampleText: resource.exampleOfExpectedContent, + textChunks, + }); if ( filteredAndRankedTextChunksResponse.status !== "ok" || @@ -267,14 +252,10 @@ const exploreResource = async (params: { const { orderedRelevantTextChunks } = filteredAndRankedTextChunksResponse; - logger.debug( - `Ordered relevant text chunks: ${stringify(orderedRelevantTextChunks)}`, - ); + logger.debug(`Ordered relevant text chunks: ${stringify(orderedRelevantTextChunks)}`); content = dedent(` - Here is a list of the most relevant sections of the PDF file with file URL ${ - resource.url - }: + Here is a list of the most relevant sections of the PDF file with file URL ${resource.url}: ${orderedRelevantTextChunks .map((text, index) => `Relevant section ${index + 1}: ${text}`) .join("\n")} @@ -345,28 +326,25 @@ const exploreResource = async (params: { `Extracted relevant ${relevantLinksFromContent.length} links from the content of the resource with URL ${resource.url}`, ); - const dereferencedEntityTypesById = - entityTypes.reduce( - (prev, schema) => ({ - ...prev, - [schema.$id]: { schema, isLink: false }, - }), - {}, - ); + const dereferencedEntityTypesById = entityTypes.reduce( + (prev, schema) => ({ + ...prev, + [schema.$id]: { schema, isLink: false }, + }), + {}, + ); - const { - claims: inferredClaimsFromContent, - entitySummaries: inferredEntitySummariesFromContent, - } = await inferSummariesThenClaimsFromText({ - existingEntitiesOfInterest, - text: content, - url: resource.url, - contentType: isResourcePdfFile ? "document" : "webpage", - title: resourceTitle ?? null, - goal: resource.goal, - dereferencedEntityTypes: dereferencedEntityTypesById, - workerIdentifiers, - }); + const { claims: inferredClaimsFromContent, entitySummaries: inferredEntitySummariesFromContent } = + await inferSummariesThenClaimsFromText({ + existingEntitiesOfInterest, + text: content, + url: resource.url, + contentType: isResourcePdfFile ? "document" : "webpage", + title: resourceTitle ?? null, + goal: resource.goal, + dereferencedEntityTypes: dereferencedEntityTypesById, + workerIdentifiers, + }); logProgress([ { @@ -473,8 +451,7 @@ export const linkFollowerAgent = async (params: { /** * Prior to exploring more resources, check if we should stop. */ - const preExploreResourcesStopCheck = - await checkIfWorkerShouldStop(workerIdentifiers); + const preExploreResourcesStopCheck = await checkIfWorkerShouldStop(workerIdentifiers); if (preExploreResourcesStopCheck.shouldStop) { /** @@ -525,9 +502,7 @@ export const linkFollowerAgent = async (params: { inferredClaims.push(...response.inferredClaims); inferredEntitySummaries.push(...response.inferredEntitySummaries); } else { - logger.debug( - `Resource at URL ${response.resource.url} not explored: ${response.reason}`, - ); + logger.debug(`Resource at URL ${response.resource.url} not explored: ${response.reason}`); if (resourcesToExplore.length === 1) { return { @@ -543,10 +518,7 @@ export const linkFollowerAgent = async (params: { } if (inferredEntitySummaries.length > 0) { - if ( - allInferredEntitySummaries.length === 0 && - resourcesToExplore.length === 1 - ) { + if (allInferredEntitySummaries.length === 0 && resourcesToExplore.length === 1) { /** * If we previously haven't encountered any entities, and we only explored * a single resource, we can safely assume that any entities inferred @@ -566,34 +538,25 @@ export const linkFollowerAgent = async (params: { ...allInferredEntitySummaries, ...inferredEntitySummaries, ].filter( - ({ localId }) => - !duplicates.some(({ duplicateIds }) => - duplicateIds.includes(localId), - ), + ({ localId }) => !duplicates.some(({ duplicateIds }) => duplicateIds.includes(localId)), ); - allInferredClaims = [...allInferredClaims, ...inferredClaims].map( - (claim) => { - const { subjectEntityLocalId, objectEntityLocalId } = claim; - const subjectDuplicate = duplicates.find(({ duplicateIds }) => - duplicateIds.includes(subjectEntityLocalId), - ); - - const objectDuplicate = objectEntityLocalId - ? duplicates.find(({ duplicateIds }) => - duplicateIds.includes(objectEntityLocalId), - ) - : undefined; - - return { - ...claim, - subjectEntityLocalId: - subjectDuplicate?.canonicalId ?? claim.subjectEntityLocalId, - objectEntityLocalId: - objectDuplicate?.canonicalId ?? objectEntityLocalId, - }; - }, - ); + allInferredClaims = [...allInferredClaims, ...inferredClaims].map((claim) => { + const { subjectEntityLocalId, objectEntityLocalId } = claim; + const subjectDuplicate = duplicates.find(({ duplicateIds }) => + duplicateIds.includes(subjectEntityLocalId), + ); + + const objectDuplicate = objectEntityLocalId + ? duplicates.find(({ duplicateIds }) => duplicateIds.includes(objectEntityLocalId)) + : undefined; + + return { + ...claim, + subjectEntityLocalId: subjectDuplicate?.canonicalId ?? claim.subjectEntityLocalId, + objectEntityLocalId: objectDuplicate?.canonicalId ?? objectEntityLocalId, + }; + }); } } @@ -617,15 +580,13 @@ export const linkFollowerAgent = async (params: { /** * Don't include duplicates */ - all.findIndex((innerLink) => areUrlsEqual(link.url, innerLink.url)) === - index, + all.findIndex((innerLink) => areUrlsEqual(link.url, innerLink.url)) === index, ); /** * Prior to asking the link follower to decide on its next actions, check if we should stop. */ - const preRequestNextActionsShouldStop = - await checkIfWorkerShouldStop(workerIdentifiers); + const preRequestNextActionsShouldStop = await checkIfWorkerShouldStop(workerIdentifiers); if (preRequestNextActionsShouldStop.shouldStop) { logProgress([ diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.optimize.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.optimize.ai.test.ts index eeb561b2dc8..7db92e85e63 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.optimize.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.optimize.ai.test.ts @@ -73,8 +73,7 @@ const ftse350Metric: MetricDefinition = { ]; const correctLinks = expectedLinks.reduce( - (acc, expectedLink) => - acc + (response.links.some(({ url }) => url === expectedLink) ? 1 : 0), + (acc, expectedLink) => acc + (response.links.some(({ url }) => url === expectedLink) ? 1 : 0), 0, ); @@ -154,8 +153,7 @@ const marksAndSpencersAnnualInvestorsReport: MetricDefinition = { ]; const correctLinks = expectedLinks.reduce( - (acc, expectedLink) => - acc + (response.links.some(({ url }) => url === expectedLink) ? 1 : 0), + (acc, expectedLink) => acc + (response.links.some(({ url }) => url === expectedLink) ? 1 : 0), 0, ); @@ -229,13 +227,10 @@ const graphicsCardSpecificationMetric: MetricDefinition = { }; } - const expectedLinks = [ - "https://www.techpowerup.com/gpu-specs/geforce-rtx-4090.c3889", - ]; + const expectedLinks = ["https://www.techpowerup.com/gpu-specs/geforce-rtx-4090.c3889"]; const correctLinks = expectedLinks.reduce( - (acc, expectedLink) => - acc + (response.links.some(({ url }) => url === expectedLink) ? 1 : 0), + (acc, expectedLink) => acc + (response.links.some(({ url }) => url === expectedLink) ? 1 : 0), 0, ); @@ -270,10 +265,7 @@ const metrics: MetricDefinition[] = [ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const baseDirectoryPath = path.join( - __dirname, - "/var/extract-links-from-text-testing", -); +const baseDirectoryPath = path.join(__dirname, "/var/extract-links-from-text-testing"); test( "Extract links form text system prompt test", diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.ts index bede4432b38..bdfaba305fb 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/choose-relevant-links-from-content.ts @@ -7,10 +7,7 @@ import { getToolCallsFromLlmAssistantMessage } from "../../../shared/get-llm-res import { graphApiClient } from "../../../shared/graph-api-client.js"; import { stripHashFromUrl } from "../shared/are-urls-equal.js"; -import type { - LlmParams, - LlmToolDefinition, -} from "../../../shared/get-llm-response/types.js"; +import type { LlmParams, LlmToolDefinition } from "../../../shared/get-llm-response/types.js"; export type Link = { url: string; @@ -134,27 +131,16 @@ export const chooseRelevantLinksFromContent = async (params: { systemPrompt?: string; }; }) => { - const { - content: unfilteredContent, - contentUrl, - contentType, - goal, - testingParams, - } = params; + const { content: unfilteredContent, contentUrl, contentType, goal, testingParams } = params; - const { userAuthentication, webId, flowEntityId, stepId } = - await getFlowContext(); + const { userAuthentication, webId, flowEntityId, stepId } = await getFlowContext(); const content = - contentType === "text" - ? unfilteredContent - : extractLinksFromHtml(unfilteredContent); + contentType === "text" ? unfilteredContent : extractLinksFromHtml(unfilteredContent); const response = await getLlmResponse( { - systemPrompt: - testingParams?.systemPrompt ?? - chooseRelevantLinksFromContentSystemPrompt, + systemPrompt: testingParams?.systemPrompt ?? chooseRelevantLinksFromContentSystemPrompt, messages: [ { role: "user", diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/filter-and-rank-text-chunks-agent.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/filter-and-rank-text-chunks-agent.ts index ae2b2b73d62..11be84dda86 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/filter-and-rank-text-chunks-agent.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/filter-and-rank-text-chunks-agent.ts @@ -5,10 +5,7 @@ import { getLlmResponse } from "../../../shared/get-llm-response.js"; import { getToolCallsFromLlmAssistantMessage } from "../../../shared/get-llm-response/llm-message.js"; import { graphApiClient } from "../../../shared/graph-api-client.js"; -import type { - LlmMessage, - LlmUserMessage, -} from "../../../shared/get-llm-response/llm-message.js"; +import type { LlmMessage, LlmUserMessage } from "../../../shared/get-llm-response/llm-message.js"; import type { LlmErrorResponse, LlmToolDefinition, @@ -37,9 +34,7 @@ const systemPrompt = dedent(` before selecting chunks. `); -const tools: LlmToolDefinition< - "submitRelevantOrderedTextChunks" | "terminate" ->[] = [ +const tools: LlmToolDefinition<"submitRelevantOrderedTextChunks" | "terminate">[] = [ { name: "submitRelevantOrderedTextChunks", description: @@ -130,8 +125,7 @@ export const filterAndRankTextChunksAgent = async (params: { } | LlmErrorResponse > => { - const { description, exampleText, textChunks, retryMessages, retryCount } = - params; + const { description, exampleText, textChunks, retryMessages, retryCount } = params; const textChunksWithIds = textChunks.map((text, index) => ({ chunkId: index.toString(), @@ -145,8 +139,7 @@ export const filterAndRankTextChunksAgent = async (params: { ${JSON.stringify(textChunksWithIds)} `); - const { flowEntityId, userAuthentication, stepId, webId } = - await getFlowContext(); + const { flowEntityId, userAuthentication, stepId, webId } = await getFlowContext(); const llmResponse = await getLlmResponse( { @@ -185,9 +178,7 @@ export const filterAndRankTextChunksAgent = async (params: { const { message } = llmResponse; - const retry = (retryParams: { - retryMessageContent: LlmUserMessage["content"]; - }) => { + const retry = (retryParams: { retryMessageContent: LlmUserMessage["content"] }) => { if (retryCount && retryCount > maxRetryCount) { return { status: "exceeded-maximum-retries" as const, @@ -213,9 +204,7 @@ export const filterAndRankTextChunksAgent = async (params: { if (!toolCall) { return await retry({ - retryMessageContent: [ - { type: "text", text: "You haven't made a tool call." }, - ], + retryMessageContent: [{ type: "text", text: "You haven't made a tool call." }], }); } @@ -232,10 +221,7 @@ export const filterAndRankTextChunksAgent = async (params: { const invalidChunkIds = relevantTextChunks .map(({ chunkId }) => chunkId) - .filter( - (chunkId) => - !textChunksWithIds.some((chunk) => chunk.chunkId === chunkId), - ); + .filter((chunkId) => !textChunksWithIds.some((chunk) => chunk.chunkId === chunkId)); if (invalidChunkIds.length > 0) { return await retry({ @@ -257,8 +243,7 @@ export const filterAndRankTextChunksAgent = async (params: { .sort((a, b) => b.relevance - a.relevance) .map( ({ chunkId: relevantChunkId }) => - textChunksWithIds.find(({ chunkId }) => chunkId === relevantChunkId)! - .text, + textChunksWithIds.find(({ chunkId }) => chunkId === relevantChunkId)!.text, ); return { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/get-link-follower-next-tool-calls.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/get-link-follower-next-tool-calls.ts index 4e7c3e9171a..8ebc84c336a 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/get-link-follower-next-tool-calls.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/get-link-follower-next-tool-calls.ts @@ -10,10 +10,7 @@ import { graphApiClient } from "../../../shared/graph-api-client.js"; import { simplifyClaimForLlmConsumption } from "../shared/simplify-for-llm-consumption.js"; import type { LlmUserMessage } from "../../../shared/get-llm-response/llm-message.js"; -import type { - LlmParams, - LlmToolDefinition, -} from "../../../shared/get-llm-response/types.js"; +import type { LlmParams, LlmToolDefinition } from "../../../shared/get-llm-response/types.js"; import type { Claim } from "../../shared/claims.js"; import type { LocalEntitySummary } from "../../shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.js"; import type { Link } from "./choose-relevant-links-from-content.js"; @@ -61,16 +58,9 @@ type GetLinkFollowerNextToolCallsParams = { possibleNextLinks: Link[]; }; -const generateUserMessage = ( - params: GetLinkFollowerNextToolCallsParams, -): LlmUserMessage => { - const { - goal, - entitySummaries, - claimsGathered, - previouslyVisitedLinks, - possibleNextLinks, - } = params; +const generateUserMessage = (params: GetLinkFollowerNextToolCallsParams): LlmUserMessage => { + const { goal, entitySummaries, claimsGathered, previouslyVisitedLinks, possibleNextLinks } = + params; return { role: "user", @@ -94,9 +84,7 @@ ${JSON.stringify( name, summary, entityTypes: entityTypeIds, - claims: JSON.stringify( - claimsAboutEntity.map(simplifyClaimForLlmConsumption), - ), + claims: JSON.stringify(claimsAboutEntity.map(simplifyClaimForLlmConsumption)), }; }), undefined, @@ -172,12 +160,7 @@ const tools: LlmToolDefinition[] = [ `), }, }, - required: [ - "url", - "reason", - "descriptionOfExpectedContent", - "exampleOfExpectedContent", - ], + required: ["url", "reason", "descriptionOfExpectedContent", "exampleOfExpectedContent"], }, }, }, @@ -195,8 +178,7 @@ const tools: LlmToolDefinition[] = [ suggestionForNextSteps: suggestionForNextStepsDefinition, explanation: { type: "string", - description: - "The reason the task is complete based on the claims gathered.", + description: "The reason the task is complete based on the claims gathered.", }, }, required: ["explanation", "suggestionForNextSteps"], @@ -217,8 +199,7 @@ const tools: LlmToolDefinition[] = [ suggestionForNextSteps: suggestionForNextStepsDefinition, explanation: { type: "string", - description: - "The reason the task cannot be progressed with the provided tools", + description: "The reason the task cannot be progressed with the provided tools", }, }, required: ["explanation", "suggestionForNextSteps"], @@ -279,8 +260,7 @@ export const getLinkFollowerNextToolCalls = async ( const userMessage = generateUserMessage(params); - const { dataSources, userAuthentication, flowEntityId, webId, stepId } = - await getFlowContext(); + const { dataSources, userAuthentication, flowEntityId, webId, stepId } = await getFlowContext(); const availableTools = dataSources.internetAccess.enabled ? tools @@ -288,8 +268,7 @@ export const getLinkFollowerNextToolCalls = async ( const response = await getLlmResponse( { - systemPrompt: - testingParams?.systemPrompt ?? getLinkFollowerNextToolCallsSystemPrompt, + systemPrompt: testingParams?.systemPrompt ?? getLinkFollowerNextToolCallsSystemPrompt, messages: [userMessage], model: testingParams?.model ?? defaultModel, toolChoice: "required", @@ -314,8 +293,7 @@ export const getLinkFollowerNextToolCalls = async ( for (const toolCall of toolCalls) { if (toolCall.name === "exploreLinks") { - for (const link of (toolCall.input as ToolCallInputs["exploreLinks"]) - .links) { + for (const link of (toolCall.input as ToolCallInputs["exploreLinks"]).links) { returnInput.links.push(link); } } else { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/index-pdf-file.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/index-pdf-file.ts index 4dc64897559..ca74a832316 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/index-pdf-file.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/index-pdf-file.ts @@ -8,10 +8,7 @@ import { VectorStoreIndex } from "llamaindex"; import md5 from "md5"; import { logger } from "../../../../shared/activity-logger.js"; -import { - createStorageContext, - persistStorageContext, -} from "./simple-storage-context.js"; +import { createStorageContext, persistStorageContext } from "./simple-storage-context.js"; import type { ReadableStream } from "node:stream/web"; @@ -58,15 +55,11 @@ export const indexPdfFile = async (params: { try { const fileStream = createWriteStream(filePath); await stream.finished( - Readable.fromWeb(response.body as ReadableStream).pipe( - fileStream, - ), + Readable.fromWeb(response.body as ReadableStream).pipe(fileStream), ); } catch (error) { await fs.unlink(filePath); - throw new Error( - `Failed to write file to file system: ${(error as Error).message}`, - ); + throw new Error(`Failed to write file to file system: ${(error as Error).message}`); } logger.info("PDF File downloaded successfully"); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/simple-storage-context.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/simple-storage-context.ts index e7c77ff7dde..82ea049baf9 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/simple-storage-context.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/link-follower-agent/llama-index/simple-storage-context.ts @@ -26,9 +26,7 @@ export const createStorageContext = async ({ hash }: { hash: string }) => { await fs.mkdir(directoryPath, { recursive: true }); } catch (error: unknown) { if ((error as NodeJS.ErrnoException).code !== "EEXIST") { - logger.info( - `Unable to create directory ${directoryPath}: ${(error as Error).message}`, - ); + logger.info(`Unable to create directory ${directoryPath}: ${(error as Error).message}`); } } diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/check-if-worker-should-stop.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/check-if-worker-should-stop.ts index c1164c1fce9..9e8ab7f098d 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/check-if-worker-should-stop.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/check-if-worker-should-stop.ts @@ -2,16 +2,10 @@ import { Context } from "@temporalio/activity"; import { parseHistoryItemPayload } from "@local/hash-backend-utils/temporal/parse-history-item-payload"; -import { - getTemporalClient, - isActivityCancelled, -} from "../../../shared/get-flow-context.js"; +import { getTemporalClient, isActivityCancelled } from "../../../shared/get-flow-context.js"; import type { FlowSignal } from "../../../../shared/signals.js"; -import type { - FlowSignalType, - WorkerIdentifiers, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { FlowSignalType, WorkerIdentifiers } from "@local/hash-isomorphic-utils/flows/types"; /** * Check if a HASH worker should stop what it is doing and return early. @@ -60,9 +54,7 @@ export const checkIfWorkerShouldStop = async ( ) { const signalData = event.workflowExecutionSignaledEventAttributes.input; - const inputData = parseHistoryItemPayload(signalData)?.[0] as - | FlowSignal - | undefined; + const inputData = parseHistoryItemPayload(signalData)?.[0] as FlowSignal | undefined; if ( inputData && diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools.ts index c135076488b..87fc62bb35e 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools.ts @@ -26,10 +26,7 @@ import type { } from "./coordinators.js"; import type { WebResourceSummary } from "./handle-web-search-tool-call.js"; import type { Subtype } from "@local/advanced-types/subtype"; -import type { - FlowDataSources, - WorkerIdentifiers, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { FlowDataSources, WorkerIdentifiers } from "@local/hash-isomorphic-utils/flows/types"; export const coordinatorToolNames = [ "complete", @@ -73,9 +70,7 @@ const explanationDefinition = { `), } as const; -export const generateToolDefinitions = < - T extends CoordinatorToolName[], ->(params: { +export const generateToolDefinitions = (params: { dataSources: FlowDataSources; omitTools?: T; state: CoordinatingAgentState | SubCoordinatingAgentState; @@ -96,10 +91,7 @@ export const generateToolDefinitions = < omitTools.push("waitForOutstandingTasks", "stopTasks"); } - const allToolDefinitions: Record< - CoordinatorToolName, - LlmToolDefinition - > = { + const allToolDefinitions: Record> = { waitForOutstandingTasks: { name: "waitForOutstandingTasks", description: @@ -164,8 +156,7 @@ export const generateToolDefinitions = < type: "array", items: { type: "string", - description: - "A question to help clarify or complete the research task", + description: "A question to help clarify or complete the research task", }, description: "An array of questions to ask the user", }, @@ -237,8 +228,7 @@ export const generateToolDefinitions = < }, webSearch: { name: "webSearch", - description: - dedent(`Perform a web search via a web search engine, returning a list of URLs. + description: dedent(`Perform a web search via a web search engine, returning a list of URLs. For best results, the query should be specific and concise. Bear in mind that all the information you require may not be available via a single web search – if you have various attributes to gather about specific entities, it may be worth performing multiple searches @@ -473,10 +463,7 @@ export type CoordinatorToolCallArguments = Subtype< >; export type ParsedCoordinatorToolCallMap = { - [K in keyof CoordinatorToolCallArguments]: ParsedLlmToolCall< - K, - CoordinatorToolCallArguments[K] - >; + [K in keyof CoordinatorToolCallArguments]: ParsedLlmToolCall; }; export type ParsedCoordinatorToolCall = @@ -624,9 +611,7 @@ export function triggerToolCallsRequests( export function triggerToolCallsRequests({ toolCalls, ...restParams -}: - | TriggerCoordinatorToolCallsRequestsParams - | TriggerSubCoordinatorToolCallsRequestsParams): +}: TriggerCoordinatorToolCallsRequestsParams | TriggerSubCoordinatorToolCallsRequestsParams): | OutstandingCoordinatorTask[] | OutstandingCoordinatorTask[] { return toolCalls.map((toolCall) => { @@ -723,8 +708,7 @@ export async function getSomeToolCallResults({ state: CoordinatingAgentState | SubCoordinatingAgentState; waitForAll: boolean; }): Promise< - | CompletedToolCall[] - | CompletedToolCall[] + CompletedToolCall[] | CompletedToolCall[] > { const outstandingShortLivedTasks = state.outstandingTasks.filter( ({ longRunning }) => !longRunning, @@ -734,19 +718,13 @@ export async function getSomeToolCallResults({ ); const readyTasks = waitForAll - ? await Promise.all( - state.outstandingTasks.map(({ resultsPromise }) => resultsPromise), - ) + ? await Promise.all(state.outstandingTasks.map(({ resultsPromise }) => resultsPromise)) : ( await Promise.all([ /** * Wait for all the short-lived tasks to complete */ - Promise.all( - outstandingShortLivedTasks.map( - ({ resultsPromise }) => resultsPromise, - ), - ), + Promise.all(outstandingShortLivedTasks.map(({ resultsPromise }) => resultsPromise)), /** * Wait for the first long-lived task to complete @@ -757,9 +735,7 @@ export async function getSomeToolCallResults({ ...(outstandingLongRunningTasks.length ? [ Promise.race( - outstandingLongRunningTasks.map( - ({ resultsPromise }) => resultsPromise, - ), + outstandingLongRunningTasks.map(({ resultsPromise }) => resultsPromise), ), ] : []), @@ -772,11 +748,7 @@ export async function getSomeToolCallResults({ await sleep(5_000); for (const outstandingTask of outstandingLongRunningTasks) { - if ( - readyTasks.find( - (readyTask) => readyTask.id === outstandingTask.toolCall.id, - ) - ) { + if (readyTasks.find((readyTask) => readyTask.id === outstandingTask.toolCall.id)) { /** we already have this one */ continue; } @@ -789,9 +761,7 @@ export async function getSomeToolCallResults({ // eslint-disable-next-line no-param-reassign state.outstandingTasks = state.outstandingTasks.filter( (outstandingTask) => - !readyTasks.find( - (readyTask) => readyTask.id === outstandingTask.toolCall.id, - ), + !readyTasks.find((readyTask) => readyTask.id === outstandingTask.toolCall.id), // this is a reasonably safe assertion for the compiler's benefit that we're not changing the array type ) as typeof state.outstandingTasks; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools/get-tool-call-results.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools/get-tool-call-results.ts index 2bd60e5f1d6..59c80d3b102 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools/get-tool-call-results.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinator-tools/get-tool-call-results.ts @@ -21,10 +21,7 @@ import type { ParsedSubCoordinatorToolCallMap, SubCoordinatingAgentToolName, } from "../coordinator-tools.js"; -import type { - CoordinatingAgentInput, - CoordinatingAgentState, -} from "../coordinators.js"; +import type { CoordinatingAgentInput, CoordinatingAgentState } from "../coordinators.js"; import type { Url } from "@blockprotocol/type-system"; import type { WorkerIdentifiers } from "@local/hash-isomorphic-utils/flows/types"; @@ -75,14 +72,8 @@ export function getToolCallResults( * so it may be worth investing the effort in a more complicated merging of results at some point. */ export async function getToolCallResults( - params: - | GetCoordinatorToolCallResultsParams - | GetSubCoordinatorToolCallResultsParams, -): Promise< - CompletedCoordinatorToolCall< - CoordinatorToolName | SubCoordinatingAgentToolName - > -> { + params: GetCoordinatorToolCallResultsParams | GetSubCoordinatorToolCallResultsParams, +): Promise> { const { stepId } = await getFlowContext(); const { agentType, input, state, toolCall, workerIdentifiers } = params; @@ -103,9 +94,7 @@ export async function getToolCallResults( }; } else if (toolCall.name === "requestHumanInput") { if (agentType === "sub-coordinator") { - throw new Error( - "Sub-coordinators cannot use the requestHumanInput tool.", - ); + throw new Error("Sub-coordinators cannot use the requestHumanInput tool."); } const { questions } = toolCall.input; @@ -119,15 +108,12 @@ export async function getToolCallResults( }; } - logger.debug( - `Requesting human input for questions: ${stringify(questions)}`, - ); + logger.debug(`Requesting human input for questions: ${stringify(questions)}`); const response = await getAnswersFromHuman(toolCall.input.questions); // eslint-disable-next-line no-param-reassign - params.state.questionsAndAnswers = - (params.state.questionsAndAnswers ?? "") + response; + params.state.questionsAndAnswers = (params.state.questionsAndAnswers ?? "") + response; return { ...nullReturns, @@ -232,9 +218,7 @@ export async function getToolCallResults( inferredClaims: response.inferredClaims, entitySummaries: response.inferredSummaries, suggestionsForNextStepsMade: [response.suggestionForNextSteps], - resourceUrlsVisited: response.exploredResources.map( - (resource) => resource.url, - ), + resourceUrlsVisited: response.exploredResources.map((resource) => resource.url), isError: response.status === "error", output: response.status === "error" @@ -256,8 +240,7 @@ export async function getToolCallResults( ); const existingClaimsAboutRelevantEntities = state.inferredClaims.filter( - ({ subjectEntityLocalId }) => - relevantEntityIds.includes(subjectEntityLocalId), + ({ subjectEntityLocalId }) => relevantEntityIds.includes(subjectEntityLocalId), ); const delegatedTaskIdentifiers = { @@ -296,12 +279,8 @@ export async function getToolCallResults( logProgress([ { type: "ClosedSubCoordinator", - errorMessage: - response.status !== "ok" ? response.explanation : undefined, - explanation: - response.status === "ok" - ? response.explanation - : response.explanation, + errorMessage: response.status !== "ok" ? response.explanation : undefined, + explanation: response.status === "ok" ? response.explanation : response.explanation, goal, output: response.status === "ok" diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinators.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinators.ts index 8a33c2c78f4..4a2547bba03 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinators.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/coordinators.ts @@ -19,10 +19,7 @@ import type { } from "./coordinator-tools.js"; import type { WebResourceSummary } from "./handle-web-search-tool-call.js"; import type { HashEntity } from "@local/hash-graph-sdk/entity"; -import type { - ProposedEntity, - WorkerIdentifiers, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { ProposedEntity, WorkerIdentifiers } from "@local/hash-isomorphic-utils/flows/types"; export const coordinatingAgentModel: LlmParams["model"] = "gpt-4o-2024-08-06"; @@ -215,9 +212,7 @@ export const processCommonStateMutationsFromToolResults = ({ ...resourceUrlsVisited, ...state.resourceUrlsVisited, ...state.outstandingTasks - .map((task) => - "url" in task.toolCall.input ? task.toolCall.input.url : null, - ) + .map((task) => ("url" in task.toolCall.input ? task.toolCall.input.url : null)) .filter((string) => string !== null), ]), ]; @@ -234,10 +229,7 @@ export const processCommonStateMutationsFromToolResults = ({ // eslint-disable-next-line no-param-reassign state.resourcesNotVisited = state.resourcesNotVisited.filter( - ({ url }) => - !state.resourceUrlsVisited.some((visitedUrl) => - areUrlsEqual(visitedUrl, url), - ), + ({ url }) => !state.resourceUrlsVisited.some((visitedUrl) => areUrlsEqual(visitedUrl, url)), ); state.webQueriesMade.push( diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-claims.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-claims.ts index 1e6e1f6c94d..2492046ac69 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-claims.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-claims.ts @@ -36,8 +36,7 @@ export const deduplicateClaims = async ( inputClaims: Claim[], proposedEntities: ProposedEntity[], ): Promise => { - const { flowEntityId, stepId, userAuthentication, webId } = - await getFlowContext(); + const { flowEntityId, stepId, userAuthentication, webId } = await getFlowContext(); /** * Simplify identification of duplicate claims. @@ -64,8 +63,7 @@ export const deduplicateClaims = async ( for (const currentClaimInLoop of inputClaims) { const entityId = currentClaimInLoop.subjectEntityLocalId; - const objectEntityId = - currentClaimInLoop.objectEntityLocalId ?? noObjectEntityIdKey; + const objectEntityId = currentClaimInLoop.objectEntityLocalId ?? noObjectEntityIdKey; claimsByEntityIdObjectAndText[entityId] ??= {}; claimsByEntityIdObjectAndText[entityId][objectEntityId] ??= {}; @@ -102,8 +100,7 @@ export const deduplicateClaims = async ( ...(currentClaimInLoop.sources ?? []).filter( (source) => !originalIdentifiedClaim.sources?.some( - (existingSource) => - existingSource.location?.uri === source.location?.uri, + (existingSource) => existingSource.location?.uri === source.location?.uri, ), ), ]; @@ -151,8 +148,7 @@ export const deduplicateClaims = async ( provenance, }); - canonicalClaimIdByDuplicateId[currentClaimInLoop.claimId] = - newClaimObject.claimId; + canonicalClaimIdByDuplicateId[currentClaimInLoop.claimId] = newClaimObject.claimId; logger.debug( `Merged claim ${JSON.stringify(currentClaimInLoop)} into ${JSON.stringify(originalIdentifiedClaim)}`, @@ -163,9 +159,7 @@ export const deduplicateClaims = async ( const subjectOfSet = new Set(proposedEntity.claims.isSubjectOf); const objectOfSet = new Set(proposedEntity.claims.isObjectOf); - for (const [duplicateId, canonicalId] of typedEntries( - canonicalClaimIdByDuplicateId, - )) { + for (const [duplicateId, canonicalId] of typedEntries(canonicalClaimIdByDuplicateId)) { if (subjectOfSet.has(duplicateId)) { subjectOfSet.delete(duplicateId); subjectOfSet.add(canonicalId); @@ -181,11 +175,8 @@ export const deduplicateClaims = async ( proposedEntity.claims.isObjectOf = [...objectOfSet]; } - const newClaimsArray = Object.values(claimsByEntityIdObjectAndText).flatMap( - (objectAndText) => - Object.values(objectAndText).flatMap((textToClaim) => - Object.values(textToClaim), - ), + const newClaimsArray = Object.values(claimsByEntityIdObjectAndText).flatMap((objectAndText) => + Object.values(objectAndText).flatMap((textToClaim) => Object.values(textToClaim)), ); return newClaimsArray; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ai.test.ts index dbdd5d80692..e0316acbe67 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ai.test.ts @@ -20,90 +20,70 @@ const ftse350EntitySummaries: LocalEntitySummary[] = [ name: "HUNTING PLC ORD 25P", summary: "HUNTING PLC, represented by the stock code HTG, has a market cap of 614.40 million GBX, a last recorded price of 452.50 GBX, and experienced a recent price change of 80.00 GBX, translating to a 21.48% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("ef7fa92d-343a-430a-9c2b-34f8aed573d1"), name: "KELLER GROUP PLC ORD 10P", summary: "KELLER GROUP PLC, symbolized by KLR, with a market capitalization of 829.01 million GBX, a last price of 1,330.00 GBX, and a recent price jump of 194.00 GBX, which is a 17.08% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("6bb3c550-82c1-4d5f-89e9-e6723a414619"), name: "BRITVIC PLC ORD 20P", summary: "BRITVIC PLC, trading under the code BVIC, has a market capitalization of 2,288.97 million GBX, with its last price at 1,021.00 GBX, and a recent price increase of 103.50 GBX, amounting to an 11.28% rise.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("4dd0da92-40a3-40fc-84db-c75aecdd0c2d"), name: "EXPERIAN PLC ORD USD0.10", summary: "EXPERIAN PLC, designated by the code EXPN, with a market cap of 31,860.88 million GBX, a closing price of 3,697.00 GBX, and a recent gain of 227.00 GBX, equivalent to a 6.54% uplift.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("a8304ece-a8cc-4373-aa2c-6ea5b00dca2b"), name: "VODAFONE GROUP PLC ORD USD0.20 20/21", summary: "VODAFONE GROUP PLC, identified by the ticker VOD, has a market capitalization of 19,844.47 million GBX, a last recorded price of 76.72 GBX, and a recent change of 3.44 GBX, marking a 4.69% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("426fa3ef-5e9b-403e-a592-a20ec0979cdc"), name: "IMPERIAL BRANDS PLC ORD 10P", summary: "IMPERIAL BRANDS PLC, under the symbol IMB, with a market cap of 16,187.35 million GBX, a last price of 1,966.00 GBX, and a recent change of 87.50 GBX, results in a 4.66% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("85ce6362-bafa-4b08-9c19-5e2c5df020f2"), name: "CMC MARKETS PLC ORD 25P", summary: "CMC MARKETS PLC, represented by CMCX, has a market capitalization of 726.12 million GBX, recorded its last price at 271.00 GBX, and saw a recent price increase of 11.50 GBX, or 4.43%.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("73faf1ef-f64c-4308-be86-8f119db77cca"), name: "SPIRAX-SARCO ENGINEERING PLC ORD 26 12/13P", summary: "SPIRAX-SARCO ENGINEERING PLC, with the ticker SPX, boasts a market capitalization of 6,831.66 million GBX, a last price of 9,615.00 GBX, and sustained a recent increase of 355.00 GBX, amounting to a 3.83% rise.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("01c487e6-5a26-47fd-90ae-da25136b3039"), name: "REDDE NORTHGATE PLC ORD 50P", summary: "REDDE NORTHGATE PLC, trading with the code REDD, has a market capitalization of 924.94 million GBX, a last price of 420.50 GBX, and observed a recent price rise of 12.50 GBX, which is a 3.06% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("55f19188-c6ff-4eea-902b-a94b9952d917"), name: "CENTRICA PLC ORD 6 14/81P", summary: "CENTRICA PLC, identified by the ticker CNA, with a market cap of 7,410.30 million GBX, having a last recorded price of 143.40 GBX, and a recent change of 4.00 GBX, reflecting a 2.87% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, ]; @@ -162,9 +142,7 @@ test.skip( expect( duplicates.find( (duplicate) => - duplicate.duplicateIds.includes( - nonDuplicateEntitySummary.localId, - ) || + duplicate.duplicateIds.includes(nonDuplicateEntitySummary.localId) || (duplicate.canonicalId === nonDuplicateEntitySummary.localId && duplicate.duplicateIds.length > 0), ), @@ -182,162 +160,125 @@ const llmProviderExistingEntitySummaries: LocalEntitySummary[] = [ name: "GPT-4o", summary: "GPT-4o is OpenAI's most advanced multimodal large language model, known for its high efficiency, speed, and cost-effectiveness.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("771c6c67-3ea4-46e3-a120-b95a89c9ca4d"), name: "GPT-4 Turbo", summary: "GPT-4 Turbo is a high-intelligence and multimodal large language model previously favored for its advanced reasoning and vision capabilities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("bd536684-597b-4368-b390-425868dd5b83"), name: "GPT-3.5 Turbo", summary: "GPT-3.5 Turbo is a fast, inexpensive large language model optimized for simple tasks and chat functionalities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("ab049eb7-894d-42ea-a063-a76144b08b71"), name: "GPT Base", summary: "GPT Base models are large language models capable of understanding and generating natural language or code without instruction following.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("3ae3cc00-eb67-41a4-9d51-fa19e0157537"), name: "gpt-4-turbo-2024-04-09", summary: "gpt-4-turbo-2024-04-09 is a version of GPT-4 Turbo with vision capabilities, supporting JSON mode and function calling.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("c5a65ece-9499-4ebf-bf33-117b7a58c6fb"), name: "gpt-4-turbo-2024-04-09", summary: "GPT-4 Turbo with Vision is the latest GPT-4 Turbo model with vision capabilities, including support for JSON mode and function calling.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("f8aea256-2e38-4c1c-b748-c6d0be878b24"), name: "gpt-4-turbo-preview", summary: "gpt-4-turbo-preview is a preview version of GPT-4 Turbo intended to reduce incomplete task responses.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("7c5d7b76-f5c8-4dd7-a88e-7f94996050aa"), name: "gpt-4-0125-preview", summary: "gpt-4-0125-preview is an earlier preview of GPT-4 Turbo, focused on reducing inadequately completed tasks.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("14fdba17-11f2-4957-a00b-3e2e8b58a2ac"), name: "gpt-4-1106-preview", summary: "gpt-4-1106-preview is a preview version of GPT-4 Turbo with improved instruction following and new features.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("06a0bad9-da61-41c0-9149-cdbb1e49c750"), name: "gpt-4-vision-preview", summary: "gpt-4-vision-preview is a preview model of GPT-4 with image understanding and other high-level capabilities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("52aa0aa0-3753-4c03-8552-f86915fa5bfe"), name: "gpt-4-1106-vision-preview", summary: "gpt-4-1106-vision-preview is a preview model of GPT-4 with image understanding and advanced functionalities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("d588f0d1-8ea1-4f18-b09e-099f1ba573eb"), name: "gpt-4", summary: "GPT-4 is a multimodal large language model known for its advanced reasoning, solving difficult problems with greater accuracy and broader general knowledge.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("02f58d32-6fa5-4055-8518-1178eaddabbb"), name: "gpt-4-0613", summary: "gpt-4-0613 is a snapshot model of GPT-4 focused on improved function calling support as of June 13, 2023.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("11a7b96a-44f0-48ee-9b88-19cd13bab94c"), name: "gpt-4-32k", summary: "gpt-4-32k is a version of GPT-4 designed for larger context windows, though not widely rolled out due to preference for GPT-4 Turbo.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("bf6aa6ae-85ea-4590-bf0e-6e9102cb69b0"), name: "gpt-4-32k-0613", summary: "gpt-4-32k-0613 is a snapshot model of GPT-4 for large context windows with better function calling support.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("1e42a1ef-d1ea-482e-97d2-37d4403591c6"), name: "gpt-3.5-turbo-0125", summary: "gpt-3.5-turbo-0125 is a version of GPT-3.5 Turbo with higher programming format accuracy and improved non-English language support.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("f20f5e21-17bb-4b27-9deb-9e04a89df33f"), name: "gpt-3.5-turbo-1106", - summary: - "gpt-3.5-turbo-1106 features improved instruction following and other enhancements.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + summary: "gpt-3.5-turbo-1106 features improved instruction following and other enhancements.", + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("244114fe-bd85-434b-a56b-20ebefed3210"), name: "gpt-3.5-turbo-instruct", summary: "GPT-3.5 Turbo Instruct is a large language model compatible with legacy Completions endpoints.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, ]; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ts index 063bc8af8b4..85ebda1a9cb 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/deduplicate-entities.ts @@ -80,8 +80,7 @@ const deduplicationAgentTool: LlmToolDefinition = { }, duplicateIds: { type: "array", - description: - "The IDs of entities that are duplicates of the canonical entity", + description: "The IDs of entities that are duplicates of the canonical entity", items: { type: "string", }, @@ -113,8 +112,7 @@ export const deduplicateEntities = async (params: { > => { const { entities, model, exceededMaxTokensAttempt } = params; - const { flowEntityId, userAuthentication, stepId, webId } = - await getFlowContext(); + const { flowEntityId, userAuthentication, stepId, webId } = await getFlowContext(); const llmResponse = await getLlmResponse( { @@ -136,9 +134,7 @@ export const deduplicateEntities = async (params: { ${entitySummary.entityTypeIds.length > 1 ? "Types" : "Type"}: ${entitySummary.entityTypeIds.join(", ")} Summary: ${entitySummary.summary} ID: ${ - "localId" in entitySummary - ? entitySummary.localId - : entitySummary.entityId + "localId" in entitySummary ? entitySummary.localId : entitySummary.entityId } `, ) @@ -212,19 +208,11 @@ export const deduplicateEntities = async (params: { const firstToolCall = toolCalls[0]; if (!firstToolCall) { - throw new Error( - `Expected tool calls in message: ${JSON.stringify(message, null, 2)}`, - ); + throw new Error(`Expected tool calls in message: ${JSON.stringify(message, null, 2)}`); } if (toolCalls.length > 1) { - throw new Error( - `Expected only one tool call in message: ${JSON.stringify( - message, - null, - 2, - )}`, - ); + throw new Error(`Expected only one tool call in message: ${JSON.stringify(message, null, 2)}`); } const { duplicates } = firstToolCall.input as { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/handle-web-search-tool-call.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/handle-web-search-tool-call.ts index a05a82d128a..c8bacc42e47 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/handle-web-search-tool-call.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/handle-web-search-tool-call.ts @@ -13,10 +13,7 @@ import type { InputNameForAiFlowAction, OutputNameForAiFlowAction, } from "@local/hash-isomorphic-utils/flows/action-definitions"; -import type { - StepInput, - WorkerIdentifiers, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { StepInput, WorkerIdentifiers } from "@local/hash-isomorphic-utils/flows/types"; export type WebResourceSummary = { url: Url; @@ -40,8 +37,7 @@ export const handleWebSearchToolCall = async (params: { payload: { kind: "Text", value: query }, }, { - inputName: - "numberOfSearchResults" satisfies InputNameForAiFlowAction<"webSearch">, + inputName: "numberOfSearchResults" satisfies InputNameForAiFlowAction<"webSearch">, payload: { kind: "Number", value: 5 }, }, ], @@ -82,15 +78,12 @@ export const handleWebSearchToolCall = async (params: { const webPageSummaryResponse = await getWebPageSummaryAction({ inputs: [ { - inputName: - "url" satisfies InputNameForAiFlowAction<"getWebPageSummary">, + inputName: "url" satisfies InputNameForAiFlowAction<"getWebPageSummary">, payload: { kind: "Text", value: url }, }, ...actionDefinitions.getWebPageSummary.inputs.flatMap( ({ name, default: defaultValue }) => - !defaultValue || name === "url" - ? [] - : [{ inputName: name, payload: defaultValue }], + !defaultValue || name === "url" ? [] : [{ inputName: name, payload: defaultValue }], ), ], }); @@ -107,8 +100,7 @@ export const handleWebSearchToolCall = async (params: { const summaryOutput = webPageSummaryOutputs?.find( ({ outputName }) => - outputName === - ("summary" satisfies OutputNameForAiFlowAction<"getWebPageSummary">), + outputName === ("summary" satisfies OutputNameForAiFlowAction<"getWebPageSummary">), ); if (!summaryOutput) { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/map-previous-coordinator-calls-to-llm-messages.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/map-previous-coordinator-calls-to-llm-messages.ts index ad3b6cf784a..185a295c5ea 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/map-previous-coordinator-calls-to-llm-messages.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/map-previous-coordinator-calls-to-llm-messages.ts @@ -11,9 +11,7 @@ import type { export const mapPreviousCoordinatorCallsToLlmMessages = (params: { includeErrorsOnly: boolean; - previousCalls: CompletedCoordinatorToolCall< - CoordinatorToolName | SubCoordinatingAgentToolName - >[]; + previousCalls: CompletedCoordinatorToolCall[]; }): LlmMessage[] => { const { includeErrorsOnly, previousCalls } = params; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ai.test.ts index 0264facdcff..a69d6f0e695 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ai.test.ts @@ -10,9 +10,7 @@ test("Test researchEntitiesAction: find subsidiary companies of Google", async ( const { userAuthentication } = await getFlowContext(); const dereferencedEntityTypes = await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], actorId: userAuthentication.actorId, graphApiClient, }); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ts index edc029f3568..53b75a2bed7 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/shared/simplify-for-llm-consumption.ts @@ -64,9 +64,7 @@ Title: ${title} Description: ${description} Properties: ${propertyTypes - .map((propertyType) => - simplifyPropertyTypeForLlmConsumption({ propertyType }), - ) + .map((propertyType) => simplifyPropertyTypeForLlmConsumption({ propertyType })) .join("\n")} `; @@ -100,13 +98,10 @@ export const simplifyProposedEntityForLlmConsumption = (params: { properties: entityProperties, } = proposedEntity; - const missingProperties = entityTypes.flatMap( - ({ schema, simplifiedPropertyTypeMappings }) => - Object.entries(schema.properties).filter( - ([simpleKey]) => - entityProperties[simplifiedPropertyTypeMappings[simpleKey]!] === - undefined, - ), + const missingProperties = entityTypes.flatMap(({ schema, simplifiedPropertyTypeMappings }) => + Object.entries(schema.properties).filter( + ([simpleKey]) => entityProperties[simplifiedPropertyTypeMappings[simpleKey]!] === undefined, + ), ); return ` @@ -115,10 +110,7 @@ export const simplifyProposedEntityForLlmConsumption = (params: { ${entityTypeIds.length > 1 ? "Entity Types" : "Entity Type"}: ${entityTypeIds.map((entityTypeId) => urlToTitleCase(entityTypeId) ?? "").join(", ")} ${Object.entries(entityProperties) - .map( - ([baseUrl, value]) => - `${urlToTitleCase(baseUrl)}: ${stringifyPropertyValue(value)}`, - ) + .map(([baseUrl, value]) => `${urlToTitleCase(baseUrl)}: ${stringifyPropertyValue(value)}`) .join("\n")} ${ diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ai.test.ts index aa28d73711c..badf5626057 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ai.test.ts @@ -1,11 +1,5 @@ import "../../../shared/testing-utilities/mock-get-flow-context.js"; -import { - existsSync, - mkdirSync, - readdirSync, - readFileSync, - writeFileSync, -} from "node:fs"; +import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -21,10 +15,7 @@ import type { SubCoordinatingAgentState } from "./sub-coordinating-agent/state.j const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const baseDirectoryPath = path.join( - __dirname, - "/var/sub-coordinating-agent/persisted-state", -); +const baseDirectoryPath = path.join(__dirname, "/var/sub-coordinating-agent/persisted-state"); export const retrievePreviousState = (params: { testName: string; @@ -50,10 +41,7 @@ export const retrievePreviousState = (params: { return JSON.parse(latestFileContent) as SubCoordinatingAgentState; }; -const persistState = (params: { - state: SubCoordinatingAgentState; - testName: string; -}) => { +const persistState = (params: { state: SubCoordinatingAgentState; testName: string }) => { const { state, testName } = params; const directoryPath = `${baseDirectoryPath}/${testName}`; @@ -77,9 +65,7 @@ test( graphApiClient, }); - const entityTypes = Object.values(dereferencedEntityTypes).map( - ({ schema }) => schema, - ); + const entityTypes = Object.values(dereferencedEntityTypes).map(({ schema }) => schema); const status = await runSubCoordinatingAgent({ input: { @@ -89,8 +75,7 @@ test( entityTypes, }, testingParams: { - persistState: (state) => - persistState({ state, testName: "github-url" }), + persistState: (state) => persistState({ state, testName: "github-url" }), resumeFromState: retrievePreviousState({ testName: "github-url", }), diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ts index ecf61efe157..18f1032c3b1 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent.ts @@ -11,10 +11,7 @@ import { type ParsedSubCoordinatorToolCall, triggerToolCallsRequests, } from "./shared/coordinator-tools.js"; -import { - processCommonStateMutationsFromToolResults, - stopWorkers, -} from "./shared/coordinators.js"; +import { processCommonStateMutationsFromToolResults, stopWorkers } from "./shared/coordinators.js"; import { deduplicateClaims } from "./shared/deduplicate-claims.js"; import { deduplicateEntities } from "./shared/deduplicate-entities.js"; import { createInitialPlan } from "./sub-coordinating-agent/create-initial-plan.js"; @@ -144,9 +141,7 @@ export const runSubCoordinatingAgent = async (params: { > => { const { toolCalls, isCleanupIteration } = processToolCallsParams; - const terminateToolCall = toolCalls.find( - (toolCall) => toolCall.name === "terminate", - ); + const terminateToolCall = toolCalls.find((toolCall) => toolCall.name === "terminate"); if (terminateToolCall) { const { explanation } = terminateToolCall.input; @@ -174,15 +169,12 @@ export const runSubCoordinatingAgent = async (params: { }), ); - const completeToolCall = toolCalls.find( - (toolCall) => toolCall.name === "complete", - ); + const completeToolCall = toolCalls.find((toolCall) => toolCall.name === "complete"); /** * Prior to initiating more requests based on the agent's tool calls, check if we should stop. */ - const preRequestToolResultsStopCheck = - await checkIfWorkerShouldStop(workerIdentifiers); + const preRequestToolResultsStopCheck = await checkIfWorkerShouldStop(workerIdentifiers); if (preRequestToolResultsStopCheck.shouldStop) { await handleStopReturn( @@ -228,8 +220,7 @@ export const runSubCoordinatingAgent = async (params: { const completedToolCalls = await getSomeToolCallResults({ state, - waitForAll: - !!completeToolCall || preRequestToolResultsStopCheck.shouldStop, + waitForAll: !!completeToolCall || preRequestToolResultsStopCheck.shouldStop, }); state.lastCompletedToolCalls = completedToolCalls; @@ -239,9 +230,7 @@ export const runSubCoordinatingAgent = async (params: { state, }); - const updatedPlan = completedToolCalls.find( - (call) => !!call.updatedPlan, - )?.updatedPlan; + const updatedPlan = completedToolCalls.find((call) => !!call.updatedPlan)?.updatedPlan; if (updatedPlan) { state.plan = updatedPlan; @@ -250,24 +239,16 @@ export const runSubCoordinatingAgent = async (params: { const newEntitySummaries = completedToolCalls.flatMap( ({ entitySummaries }) => entitySummaries ?? [], ); - const newClaims = completedToolCalls.flatMap( - ({ inferredClaims }) => inferredClaims ?? [], - ); + const newClaims = completedToolCalls.flatMap(({ inferredClaims }) => inferredClaims ?? []); state.inferredClaims = [...state.inferredClaims, ...newClaims]; if (newEntitySummaries.length > 0) { const { duplicates } = await deduplicateEntities({ - entities: [ - ...input.relevantEntities, - ...newEntitySummaries, - ...state.entitySummaries, - ], + entities: [...input.relevantEntities, ...newEntitySummaries, ...state.entitySummaries], }); - const existingEntityIds = input.relevantEntities.map( - ({ localId }) => localId, - ); + const existingEntityIds = input.relevantEntities.map(({ localId }) => localId); const adjustedDuplicates = duplicates.map( ({ canonicalId, duplicateIds }) => { @@ -287,9 +268,7 @@ export const runSubCoordinatingAgent = async (params: { return { canonicalId: existingEntityIdMarkedAsDuplicate, duplicateIds: [ - ...duplicateIds.filter( - (id) => id !== existingEntityIdMarkedAsDuplicate, - ), + ...duplicateIds.filter((id) => id !== existingEntityIdMarkedAsDuplicate), canonicalId, ], }; @@ -299,41 +278,29 @@ export const runSubCoordinatingAgent = async (params: { }, ); - const inferredClaimsWithDeduplicatedEntities = state.inferredClaims.map( - (claim) => { - const { subjectEntityLocalId, objectEntityLocalId } = claim; - const subjectDuplicate = adjustedDuplicates.find(({ duplicateIds }) => - duplicateIds.includes(subjectEntityLocalId), - ); + const inferredClaimsWithDeduplicatedEntities = state.inferredClaims.map((claim) => { + const { subjectEntityLocalId, objectEntityLocalId } = claim; + const subjectDuplicate = adjustedDuplicates.find(({ duplicateIds }) => + duplicateIds.includes(subjectEntityLocalId), + ); - const objectDuplicate = objectEntityLocalId - ? duplicates.find(({ duplicateIds }) => - duplicateIds.includes(objectEntityLocalId), - ) - : undefined; - - return { - ...claim, - subjectEntityLocalId: - subjectDuplicate?.canonicalId ?? claim.subjectEntityLocalId, - objectEntityLocalId: - objectDuplicate?.canonicalId ?? objectEntityLocalId, - }; - }, - ); + const objectDuplicate = objectEntityLocalId + ? duplicates.find(({ duplicateIds }) => duplicateIds.includes(objectEntityLocalId)) + : undefined; + + return { + ...claim, + subjectEntityLocalId: subjectDuplicate?.canonicalId ?? claim.subjectEntityLocalId, + objectEntityLocalId: objectDuplicate?.canonicalId ?? objectEntityLocalId, + }; + }); state.inferredClaims.push(...inferredClaimsWithDeduplicatedEntities); state.inferredClaims = await deduplicateClaims(state.inferredClaims, []); - state.entitySummaries = [ - ...state.entitySummaries, - ...newEntitySummaries, - ].filter( - ({ localId }) => - !duplicates.some(({ duplicateIds }) => - duplicateIds.includes(localId), - ), + state.entitySummaries = [...state.entitySummaries, ...newEntitySummaries].filter( + ({ localId }) => !duplicates.some(({ duplicateIds }) => duplicateIds.includes(localId)), ); } @@ -358,8 +325,7 @@ export const runSubCoordinatingAgent = async (params: { * Prior to asking the coordinator to decide on its next actions, check if we should stop. * We checked before waiting for outstanding tasks, but we may have received a stop signal from the coordinator since. */ - const preRequestNextActionsShouldStop = - await checkIfWorkerShouldStop(workerIdentifiers); + const preRequestNextActionsShouldStop = await checkIfWorkerShouldStop(workerIdentifiers); if (preRequestNextActionsShouldStop.shouldStop) { await handleStopReturn( preRequestNextActionsShouldStop, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/create-initial-plan.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/create-initial-plan.ts index f637fda1e5c..6060cac9e82 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/create-initial-plan.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/create-initial-plan.ts @@ -5,10 +5,7 @@ import { getLlmResponse } from "../../../shared/get-llm-response.js"; import { getToolCallsFromLlmAssistantMessage } from "../../../shared/get-llm-response/llm-message.js"; import { graphApiClient } from "../../../shared/graph-api-client.js"; import { coordinatingAgentModel } from "../shared/coordinators.js"; -import { - generateInitialUserMessage, - generateSystemPromptPrefix, -} from "./generate-messages.js"; +import { generateInitialUserMessage, generateSystemPromptPrefix } from "./generate-messages.js"; import { generateToolDefinitions } from "./sub-coordinator-tools.js"; import type { @@ -30,8 +27,7 @@ export const createInitialPlan = async (params: { Do not make any other tool calls. `); - const { dataSources, userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { dataSources, userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const tools = Object.values( generateToolDefinitions({ @@ -62,18 +58,14 @@ export const createInitialPlan = async (params: { ); if (llmResponse.status !== "ok") { - throw new Error( - `Failed to get LLM response: ${JSON.stringify(llmResponse)}`, - ); + throw new Error(`Failed to get LLM response: ${JSON.stringify(llmResponse)}`); } const { message } = llmResponse; const toolCalls = getToolCallsFromLlmAssistantMessage({ message }); - const updatePlanToolCall = toolCalls.find( - (toolCall) => toolCall.name === "updatePlan", - ); + const updatePlanToolCall = toolCalls.find((toolCall) => toolCall.name === "updatePlan"); if (updatePlanToolCall) { const { plan } = @@ -83,8 +75,6 @@ export const createInitialPlan = async (params: { } throw new Error( - `Could not find "updatePlan" tool call in LLM response: ${JSON.stringify( - llmResponse, - )}`, + `Could not find "updatePlan" tool call in LLM response: ${JSON.stringify(llmResponse)}`, ); }; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/generate-messages.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/generate-messages.ts index dbbed5c9641..9ffa6e5103c 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/generate-messages.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/generate-messages.ts @@ -13,11 +13,8 @@ import type { import type { SubCoordinatingAgentInput } from "./input.js"; import type { SubCoordinatingAgentState } from "./state.js"; -export const generateSystemPromptPrefix = (params: { - input: SubCoordinatingAgentInput; -}) => { - const { relevantEntities, existingClaimsAboutRelevantEntities } = - params.input; +export const generateSystemPromptPrefix = (params: { input: SubCoordinatingAgentInput }) => { + const { relevantEntities, existingClaimsAboutRelevantEntities } = params.input; return dedent(` You are a researcher tasked with discovering claims about entities to satisfy a research goal. @@ -49,12 +46,7 @@ export const generateSystemPromptPrefix = (params: { export const generateInitialUserMessage = (params: { input: SubCoordinatingAgentInput; }): LlmUserMessage => { - const { - goal, - relevantEntities, - existingClaimsAboutRelevantEntities, - entityTypes, - } = params.input; + const { goal, relevantEntities, existingClaimsAboutRelevantEntities, entityTypes } = params.input; return { role: "user", @@ -64,9 +56,7 @@ export const generateInitialUserMessage = (params: { text: dedent(` ${goal} -${entityTypes - .map((entityType) => simplifyEntityTypeForLlmConsumption({ entityType })) - .join("\n")} +${entityTypes.map((entityType) => simplifyEntityTypeForLlmConsumption({ entityType })).join("\n")} ${ relevantEntities.length > 0 @@ -82,10 +72,7 @@ ${ Summary: ${summary} ${entityTypeIds.length > 1 ? "Entity Types" : "Entity Type"}: ${entityTypeIds.join(", ")} Claims known at start of task: ${claimsAboutEntity - .map( - (claim) => - `${simplifyClaimForLlmConsumption(claim)}`, - ) + .map((claim) => `${simplifyClaimForLlmConsumption(claim)}`) .join("\n")} `); }) diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/request-sub-coordinator-actions.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/request-sub-coordinator-actions.ts index 2ddf94fc061..3691d26e17e 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/request-sub-coordinator-actions.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/request-sub-coordinator-actions.ts @@ -36,11 +36,10 @@ export const requestSubCoordinatorActions = async (params: { Make as many tool calls as are required to progress towards completing the task. `); - const llmMessagesFromPreviousToolCalls = - mapPreviousCoordinatorCallsToLlmMessages({ - includeErrorsOnly: true, - previousCalls: state.lastCompletedToolCalls, - }); + const llmMessagesFromPreviousToolCalls = mapPreviousCoordinatorCallsToLlmMessages({ + includeErrorsOnly: true, + previousCalls: state.lastCompletedToolCalls, + }); const progressReport = generateProgressReport({ input, state }); @@ -55,15 +54,12 @@ export const requestSubCoordinatorActions = async (params: { content: [progressReport], }); - const { dataSources, userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { dataSources, userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const tools = Object.values( generateToolDefinitions({ dataSources, - omitTools: [ - ...(state.inferredClaims.length > 0 ? [] : ["complete" as const]), - ], + omitTools: [...(state.inferredClaims.length > 0 ? [] : ["complete" as const])], state, }), ); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/state.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/state.ts index b1153e63926..1d74faded03 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/state.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/state.ts @@ -3,10 +3,7 @@ import type { ParsedSubCoordinatorToolCall, SubCoordinatingAgentToolName, } from "../shared/coordinator-tools.js"; -import type { - CoordinatingAgentState, - OutstandingCoordinatorTask, -} from "../shared/coordinators.js"; +import type { CoordinatingAgentState, OutstandingCoordinatorTask } from "../shared/coordinators.js"; export type SubCoordinatingAgentState = Pick< CoordinatingAgentState, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/sub-coordinator-tools.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/sub-coordinator-tools.ts index 5f5597110ff..4721ed3a5ee 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/sub-coordinator-tools.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/research-entities-action/sub-coordinating-agent/sub-coordinator-tools.ts @@ -14,9 +14,7 @@ import type { FlowDataSources } from "@local/hash-isomorphic-utils/flows/types"; /** * Generate tool definitions for the sub-coordinating agent, to be passed to the LLM. */ -export const generateToolDefinitions = < - T extends SubCoordinatingAgentCustomToolName[], ->(params: { +export const generateToolDefinitions = (params: { dataSources: FlowDataSources; omitTools: T; state: SubCoordinatingAgentState; @@ -41,8 +39,7 @@ export const generateToolDefinitions = < properties: { explanation: { type: "string", - description: - "The explanation for how the gathered claims satisfy the research task.", + description: "The explanation for how the gathered claims satisfy the research task.", }, }, }, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/claims.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/claims.ts index aef79732c02..a77e7576ae1 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/claims.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/claims.ts @@ -11,7 +11,5 @@ export type Claim = { export const claimTextualContentFromClaim = (claim: Claim): string => `${claim.text}${ - claim.prepositionalPhrases.length - ? `– ${claim.prepositionalPhrases.join(", ")}` - : "" + claim.prepositionalPhrases.length ? `– ${claim.prepositionalPhrases.join(", ")}` : "" }`; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/create-file-entity-from-url.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/create-file-entity-from-url.ts index 58fd294c2fe..4543e5691d4 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/create-file-entity-from-url.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/create-file-entity-from-url.ts @@ -1,9 +1,4 @@ -import { - createReadStream, - createWriteStream, - mkdirSync, - statSync, -} from "node:fs"; +import { createReadStream, createWriteStream, mkdirSync, statSync } from "node:fs"; import { unlink } from "node:fs/promises"; import * as http from "node:http"; import * as https from "node:https"; @@ -14,10 +9,7 @@ import { finished } from "node:stream/promises"; import mime from "mime-types"; -import { - formatFileUrl, - getEntityTypeIdForMimeType, -} from "@local/hash-backend-utils/file-storage"; +import { formatFileUrl, getEntityTypeIdForMimeType } from "@local/hash-backend-utils/file-storage"; import { getStorageProvider } from "@local/hash-backend-utils/flows/payload-storage"; import { getWebMachineId } from "@local/hash-backend-utils/machine-actors"; import { validateExternalUrlWithDnsCheck } from "@local/hash-backend-utils/url-validation"; @@ -41,10 +33,7 @@ import type { ProvidedEntityEditionProvenance, VersionedUrl, } from "@blockprotocol/type-system"; -import type { - File, - FileProperties, -} from "@local/hash-isomorphic-utils/system-types/shared"; +import type { File, FileProperties } from "@local/hash-isomorphic-utils/system-types/shared"; import type { ReadableStream } from "node:stream/web"; const baseFilePath = path.join(tmpdir(), "hash-tmp-files"); @@ -62,17 +51,11 @@ const downloadFileToFileSystem = async (fileUrl: string) => { try { const fileStream = createWriteStream(filePath); - await finished( - Readable.fromWeb(response.body as ReadableStream).pipe( - fileStream, - ), - ); + await finished(Readable.fromWeb(response.body as ReadableStream).pipe(fileStream)); return filePath; } catch (error) { await unlink(filePath).catch(() => {}); - throw new Error( - `Failed to write file to file system: ${(error as Error).message}`, - ); + throw new Error(`Failed to write file to file system: ${(error as Error).message}`); } }; @@ -101,11 +84,7 @@ const writeFileToS3URL = async ({ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { resolve("Ok"); } else { - reject( - new Error( - `${res.statusCode} Error uploading to S3: ${res.statusMessage}`, - ), - ); + reject(new Error(`${res.statusCode} Error uploading to S3: ${res.statusMessage}`)); } }); }, @@ -115,9 +94,7 @@ const writeFileToS3URL = async ({ reject(new Error(`Request error: ${error.message}`)); }); - fileStream.on("error", (error) => - reject(new Error(`Error reading file: ${error.message}`)), - ); + fileStream.on("error", (error) => reject(new Error(`Error reading file: ${error.message}`))); fileStream.pipe(req); fileStream.on("end", () => req.end()); }); @@ -153,8 +130,7 @@ export const createFileEntityFromUrl = async (params: { provenance: provenanceFromParams, } = params; - const { userAuthentication, webId, flowEntityId, stepId } = - await getFlowContext(); + const { userAuthentication, webId, flowEntityId, stepId } = await getFlowContext(); const urlValidation = await validateExternalUrlWithDnsCheck(originalUrl); if (!urlValidation.valid) { @@ -168,17 +144,13 @@ export const createFileEntityFromUrl = async (params: { const urlObject = new URL(originalUrl); const urlWithoutParams = new URL(urlObject.origin + urlObject.pathname); - const filename = normalizeWhitespace( - urlWithoutParams.pathname.split("/").pop()!, - ); + const filename = normalizeWhitespace(urlWithoutParams.pathname.split("/").pop()!); let localFilePath; try { localFilePath = await downloadFileToFileSystem(originalUrl); } catch (err) { - const message = `Error downloading file from URL: ${ - (err as Error).message - }`; + const message = `Error downloading file from URL: ${(err as Error).message}`; logger.error(message); @@ -193,9 +165,7 @@ export const createFileEntityFromUrl = async (params: { const mimeTypeEntityTypeId = getEntityTypeIdForMimeType(mimeType); const entityTypeIds = params.entityTypeIds ?? - (mimeTypeEntityTypeId - ? [mimeTypeEntityTypeId] - : [systemEntityTypes.file.entityTypeId]); + (mimeTypeEntityTypeId ? [mimeTypeEntityTypeId] : [systemEntityTypes.file.entityTypeId]); const stats = statSync(localFilePath); const fileSizeInBytes = stats.size; @@ -203,22 +173,15 @@ export const createFileEntityFromUrl = async (params: { const initialProperties: FileProperties = { "https://blockprotocol.org/@blockprotocol/types/property-type/description/": description ?? undefined, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": - filename, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": filename, "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": displayName ?? filename, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": - originalUrl, - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": - mimeType, - "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/": - filename, - "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/": - "URL", - "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/": - originalUrl, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/": - fileSizeInBytes, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": originalUrl, + "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": mimeType, + "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/": filename, + "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/": "URL", + "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/": originalUrl, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/": fileSizeInBytes, }; const isAiGenerated = provenanceFromParams?.actorType === "ai"; @@ -243,20 +206,17 @@ export const createFileEntityFromUrl = async (params: { }); if (!webBotActorId) { - throw new Error( - `Could not get ${isAiGenerated ? "AI" : "web"} bot for web ${webId}`, - ); + throw new Error(`Could not get ${isAiGenerated ? "AI" : "web"} bot for web ${webId}`); } - const provenance: ProvidedEntityEditionProvenance = - provenanceFromParams ?? { - actorType: "machine", - origin: { - type: "flow", - id: flowEntityId, - stepIds: [stepId], - }, - }; + const provenance: ProvidedEntityEditionProvenance = provenanceFromParams ?? { + actorType: "machine", + origin: { + type: "flow", + id: flowEntityId, + stepIds: [stepId], + }, + }; const incompleteFileEntity = await HashEntity.create( graphApiClient, @@ -264,13 +224,8 @@ export const createFileEntityFromUrl = async (params: { { draft: false, webId, - properties: mergePropertyObjectAndMetadata( - initialProperties, - propertyMetadata, - ), - entityTypeIds: entityTypeIds as [ - typeof systemEntityTypes.file.entityTypeId, - ], + properties: mergePropertyObjectAndMetadata(initialProperties, propertyMetadata), + entityTypeIds: entityTypeIds as [typeof systemEntityTypes.file.entityTypeId], provenance, }, ); @@ -285,27 +240,25 @@ export const createFileEntityFromUrl = async (params: { filename, }); - const { fileStorageProperties, presignedPut } = - await storageProvider.presignUpload({ - expiresInSeconds: 60 * 60 * 24, // 24 hours - headers: { - "content-length": fileSizeInBytes, - "content-type": mimeType, - }, - key, - }); + const { fileStorageProperties, presignedPut } = await storageProvider.presignUpload({ + expiresInSeconds: 60 * 60 * 24, // 24 hours + headers: { + "content-length": fileSizeInBytes, + "content-type": mimeType, + }, + key, + }); const updatedProperties: File["propertiesWithMetadata"] = { ...fileStorageProperties, value: { ...fileStorageProperties.value, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": - { - value: formatFileUrl(key), - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": { + value: formatFileUrl(key), + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", }, + }, }, }; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/graph-requests.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/graph-requests.ts index c3cf62c2552..c8b90fa7861 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/graph-requests.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/graph-requests.ts @@ -1,9 +1,6 @@ import isEqual from "lodash/isEqual.js"; -import { - extractDraftIdFromEntityId, - splitEntityId, -} from "@blockprotocol/type-system"; +import { extractDraftIdFromEntityId, splitEntityId } from "@blockprotocol/type-system"; import { typedEntries } from "@local/advanced-types/typed-entries"; import { queryEntities } from "@local/hash-graph-sdk/entity"; import { currentTimeInstantTemporalAxes } from "@local/hash-isomorphic-utils/graph-queries"; @@ -80,19 +77,15 @@ export const getEntityUpdate = ({ let isExactMatch = true; - for (const [key, propertyWithMetadata] of typedEntries( - newPropertiesWithMetadata.value, - )) { + for (const [key, propertyWithMetadata] of typedEntries(newPropertiesWithMetadata.value)) { if (!existingEntity.properties[key]) { isExactMatch = false; } - const newPropertySources = - propertyWithMetadata.metadata?.provenance?.sources; + const newPropertySources = propertyWithMetadata.metadata?.provenance?.sources; const existingPropertySources = - existingEntity.propertiesMetadata.value[key]?.metadata?.provenance - ?.sources; + existingEntity.propertiesMetadata.value[key]?.metadata?.provenance?.sources; let sourcesToApply = newPropertySources; @@ -137,9 +130,7 @@ export const getEntityUpdate = ({ }); } - const existingEntityIsDraft = !!extractDraftIdFromEntityId( - existingEntity.entityId, - ); + const existingEntityIsDraft = !!extractDraftIdFromEntityId(existingEntity.entityId); return { existingEntityIsDraft, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text.ts index be14daac842..13db1dc731b 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text.ts @@ -74,16 +74,13 @@ export const inferSummariesThenClaimsFromText = async (params: { workerIdentifiers, } = params; - const { entitySummaries: newEntitySummaries } = - await getEntitySummariesFromText({ - existingSummaries: existingEntitiesOfInterest, - text, - dereferencedEntityTypes: Object.values(dereferencedEntityTypes).map( - (type) => type.schema, - ), - relevantEntitiesPrompt: goal, - testingParams, - }); + const { entitySummaries: newEntitySummaries } = await getEntitySummariesFromText({ + existingSummaries: existingEntitiesOfInterest, + text, + dereferencedEntityTypes: Object.values(dereferencedEntityTypes).map((type) => type.schema), + relevantEntitiesPrompt: goal, + testingParams, + }); const entitySummariesForInferenceByType = [ ...newEntitySummaries, @@ -123,33 +120,24 @@ export const inferSummariesThenClaimsFromText = async (params: { return await Promise.all( entitySummariesOfType.map(async (entity) => { - const { claims: claimsForSingleEntity } = - await inferEntityClaimsFromTextAgent({ - subjectEntities: [entity], - linkEntityTypesById: Object.fromEntries( - Object.entries(dereferencedEntityTypes) - .filter(([linkEntityTypeId]) => - Object.keys(dereferencedEntityType.links ?? {}).includes( - linkEntityTypeId, - ), - ) - .map(([linkEntityTypeId, linkEntity]) => [ - linkEntityTypeId, - linkEntity.schema, - ]), - ), - potentialObjectEntities: [ - ...newEntitySummaries, - ...existingEntitiesOfInterest, - ], - goal, - text, - title, - url: url as Url, - contentType, - dereferencedEntityType, - workerIdentifiers, - }); + const { claims: claimsForSingleEntity } = await inferEntityClaimsFromTextAgent({ + subjectEntities: [entity], + linkEntityTypesById: Object.fromEntries( + Object.entries(dereferencedEntityTypes) + .filter(([linkEntityTypeId]) => + Object.keys(dereferencedEntityType.links ?? {}).includes(linkEntityTypeId), + ) + .map(([linkEntityTypeId, linkEntity]) => [linkEntityTypeId, linkEntity.schema]), + ), + potentialObjectEntities: [...newEntitySummaries, ...existingEntitiesOfInterest], + goal, + text, + title, + url: url as Url, + contentType, + dereferencedEntityType, + workerIdentifiers, + }); return claimsForSingleEntity; }), diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ai.test.ts index 34a1073311b..25377b9044b 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ai.test.ts @@ -22,15 +22,12 @@ test( const { userAuthentication } = await getFlowContext(); const dereferencedEntityTypes = await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], actorId: userAuthentication.actorId, graphApiClient, }); - const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]! - .schema; + const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]!.schema; const webPage = await getWebPageActivity({ url: "https://www.londonstockexchange.com/indices/ftse-350/constituents/table" as Url, @@ -76,8 +73,7 @@ test( graphApiClient, }); - const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]! - .schema; + const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]!.schema; const webPage = await getWebPageActivity({ url: "https://openai.com/index/video-generation-models-as-world-simulators/" as Url, @@ -117,8 +113,7 @@ test( graphApiClient, }); - const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]! - .schema; + const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]!.schema; const webPage = await getWebPageActivity({ url: "https://churchlab.hms.harvard.edu/index.php/lab-members#current" as Url, @@ -135,8 +130,7 @@ test( text: htmlContent, dereferencedEntityTypes: [dereferencedEntityType], existingSummaries: [], - relevantEntitiesPrompt: - "Obtain the full list of the current members of Church Lab", + relevantEntitiesPrompt: "Obtain the full list of the current members of Church Lab", }); expect(entitySummaries).toBeDefined(); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize.ai.test.ts index 33784fe80dd..4d7a9feafe8 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize.ai.test.ts @@ -45,33 +45,20 @@ const metrics: MetricDefinition[] = testData.map((testItem) => { text: context, }); - const entitySummarySet = new Set( - entitySummaries.map((entitySummary) => entitySummary.name), - ); + const entitySummarySet = new Set(entitySummaries.map((entitySummary) => entitySummary.name)); /** * @todo update this for the new entity summary approach, checking instead if any of the gold or irrelevant entities * are present in the inferred summaries but haven't had the correct, existing Company type assigned. */ - const wrongTypeEntitiesTestSet = new Set( - wrongTypeEntities.map((entity) => entity.name), - ); - const wrongTypeEntitiesIdentified = entitySummarySet.intersection( - wrongTypeEntitiesTestSet, - ); - - const goldEntitiesTestSet = new Set( - goldEntities.map((entity) => entity.name), - ); - const missingGoldEntities = - goldEntitiesTestSet.difference(entitySummarySet); - - const irrelevantEntitiesTestSet = new Set( - irrelevantEntities.map((entity) => entity.name), - ); - const irrelevantEntitiesIdentified = entitySummarySet.intersection( - irrelevantEntitiesTestSet, - ); + const wrongTypeEntitiesTestSet = new Set(wrongTypeEntities.map((entity) => entity.name)); + const wrongTypeEntitiesIdentified = entitySummarySet.intersection(wrongTypeEntitiesTestSet); + + const goldEntitiesTestSet = new Set(goldEntities.map((entity) => entity.name)); + const missingGoldEntities = goldEntitiesTestSet.difference(entitySummarySet); + + const irrelevantEntitiesTestSet = new Set(irrelevantEntities.map((entity) => entity.name)); + const irrelevantEntitiesIdentified = entitySummarySet.intersection(irrelevantEntitiesTestSet); let score = 1; @@ -93,15 +80,12 @@ const metrics: MetricDefinition[] = testData.map((testItem) => { } const missingEntitiesPenalty = testDataHasGoldEntities - ? missingEntitiesMultiplier * - (missingGoldEntities.size / goldEntitiesTestSet.size) + ? missingEntitiesMultiplier * (missingGoldEntities.size / goldEntitiesTestSet.size) : 0; score -= missingEntitiesPenalty; - const irrelevantEntitiesMultiplier = testDataHasIrrelevantEntities - ? 0.2 - : 0; + const irrelevantEntitiesMultiplier = testDataHasIrrelevantEntities ? 0.2 : 0; const irrelevantEntitiesPenalty = testDataHasIrrelevantEntities ? irrelevantEntitiesMultiplier * @@ -128,9 +112,7 @@ const metrics: MetricDefinition[] = testData.map((testItem) => { wrongTypeEntitiesIdentified.size } entities of an incorrect type, identified ${ goldEntitiesTestSet.size - missingGoldEntities.size - } out of a possible ${ - goldEntitiesTestSet.size - } target entities, and identified ${ + } out of a possible ${goldEntitiesTestSet.size} target entities, and identified ${ irrelevantEntitiesIdentified.size } entities which were of the right type but didn't meet the research prompt.`, testingParams, @@ -142,10 +124,7 @@ const metrics: MetricDefinition[] = testData.map((testItem) => { const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const baseDirectoryPath = path.join( - __dirname, - "/var/get-entity-summaries-from-text-test", -); +const baseDirectoryPath = path.join(__dirname, "/var/get-entity-summaries-from-text-test"); test( "Get entity summaries from text system prompt test", diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize/test-data.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize/test-data.ts index 86adb731aff..c8b1edf3177 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize/test-data.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.optimize/test-data.ts @@ -93,8 +93,7 @@ export const testData: { }, { name: "Tesla", - description: - "Company founded by Elon Musk, which Musk wanted to integrate with OpenAI.", + description: "Company founded by Elon Musk, which Musk wanted to integrate with OpenAI.", }, { name: "Microsoft", @@ -103,8 +102,7 @@ export const testData: { }, { name: "Apple", - description: - "Company partnered with OpenAI to integrate ChatGPT with Siri.", + description: "Company partnered with OpenAI to integrate ChatGPT with Siri.", }, ], irrelevantEntities: [ @@ -136,23 +134,19 @@ export const testData: { wrongTypeEntities: [ { name: "Elon Musk", - description: - "CEO and entrepreneur involved in the lawsuit against OpenAI.", + description: "CEO and entrepreneur involved in the lawsuit against OpenAI.", }, { name: "Sam Altman", - description: - "CEO of OpenAI, involved in the legal dispute with Elon Musk.", + description: "CEO of OpenAI, involved in the legal dispute with Elon Musk.", }, { name: "Greg Brockman", - description: - "Co-founder and president of OpenAI, mentioned in Elon Musk's lawsuit.", + description: "Co-founder and president of OpenAI, mentioned in Elon Musk's lawsuit.", }, { name: "Sam Altman", - description: - "CEO of OpenAI, involved in the temporary leadership crisis.", + description: "CEO of OpenAI, involved in the temporary leadership crisis.", }, { name: "Clare Duffy", @@ -475,8 +469,7 @@ export const testData: { }, { name: "Xavier Portillo", - description: - "Kavli-Laukien Postdoctoral Fellow at the Origins of Life Initiative", + description: "Kavli-Laukien Postdoctoral Fellow at the Origins of Life Initiative", }, { name: "Jacob (Jake) Potts", @@ -686,8 +679,7 @@ export const testData: { description: "A written or printed work consisting of pages glued or sewn together along one side and bound in covers.", }, - relevantEntitiesPrompt: - "Books authored by Jane Doe (excluding anthologies).", + relevantEntitiesPrompt: "Books authored by Jane Doe (excluding anthologies).", context: "

Jane Doe: A Literary Journey

Exploring Her Masterpieces

Jane Doe has captivated readers with her unique storytelling and compelling characters. Some of her most celebrated works include 'The Lost Paradise' and 'Echoes of the Past'.

Recent Releases

In 2023, she released 'Whispers in the Wind', a novel that quickly became a bestseller. Her latest book, 'Shadows of Time', was published in January 2024 and has received rave reviews.

Other Notable Works

Aside from her own novels, Jane Doe has also contributed to anthologies such as 'Tales of the Unseen' and 'Mystery Writers Unite'.

Similar books include 'The Silent Forest' by John Smith and 'Ocean's Call' by Mary Johnson.

About Jane Doe

Jane Doe's influence in the literary world extends beyond her novels. She has also written several academic papers on literature and teaches creative writing at a prestigious university.

© 2024 Book Lovers

", goldEntities: [ @@ -802,8 +794,7 @@ export const testData: { }, { name: "Ada Lovelace", - description: - "Architecture for NVIDIA's GeForce RTX 4090 graphics card.", + description: "Architecture for NVIDIA's GeForce RTX 4090 graphics card.", }, { name: "NVIDIA Studio", @@ -811,13 +802,11 @@ export const testData: { }, { name: "NVIDIA Encoder", - description: - "Technology for high-quality broadcasting in NVIDIA graphics cards.", + description: "Technology for high-quality broadcasting in NVIDIA graphics cards.", }, { name: "Ray Tracing Cores", - description: - "Dedicated cores for realistic graphics rendering in NVIDIA GPUs.", + description: "Dedicated cores for realistic graphics rendering in NVIDIA GPUs.", }, ], }, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ts index 7830a64cec1..b186b4cf625 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ts @@ -9,15 +9,8 @@ import { getToolCallsFromLlmAssistantMessage } from "../../../shared/get-llm-res import { graphApiClient } from "../../../shared/graph-api-client.js"; import type { DereferencedEntityType } from "../../../shared/dereference-entity-type.js"; -import type { - LlmParams, - LlmToolDefinition, -} from "../../../shared/get-llm-response/types.js"; -import type { - EntityId, - EntityUuid, - VersionedUrl, -} from "@blockprotocol/type-system"; +import type { LlmParams, LlmToolDefinition } from "../../../shared/get-llm-response/types.js"; +import type { EntityId, EntityUuid, VersionedUrl } from "@blockprotocol/type-system"; export type LocalEntitySummary = { localId: EntityId; @@ -31,10 +24,7 @@ const toolNames = ["registerEntitySummaries"] as const; type ToolName = (typeof toolNames)[number]; const generateToolDefinitions = (params: { - dereferencedEntityTypes: Pick< - DereferencedEntityType, - "$id" | "title" | "description" - >[]; + dereferencedEntityTypes: Pick[]; }): Record> => ({ registerEntitySummaries: { name: "registerEntitySummaries", @@ -133,10 +123,7 @@ export const getEntitySummariesFromText = async (params: { * All entity types which have been given as inputs to the research task, * i.e. the type of entities we are looking for. */ - dereferencedEntityTypes: Pick< - DereferencedEntityType, - "$id" | "title" | "description" - >[]; + dereferencedEntityTypes: Pick[]; /** * Any existing entities we already know about and don't need to create new summaries for. */ @@ -163,8 +150,7 @@ export const getEntitySummariesFromText = async (params: { testingParams, } = params; - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const toolDefinitions = generateToolDefinitions({ dereferencedEntityTypes, @@ -225,8 +211,7 @@ export const getEntitySummariesFromText = async (params: { ], }, ], - systemPrompt: - testingParams?.systemPrompt ?? entitySummariesFromTextSystemPrompt, + systemPrompt: testingParams?.systemPrompt ?? entitySummariesFromTextSystemPrompt, tools: Object.values(toolDefinitions), }, { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text-agent.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text-agent.ts index 9952e7e929a..43b16974884 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text-agent.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text-agent.ts @@ -19,10 +19,7 @@ import type { LlmMessageToolResultContent, LlmUserMessage, } from "../../../shared/get-llm-response/llm-message.js"; -import type { - LlmParams, - LlmToolDefinition, -} from "../../../shared/get-llm-response/types.js"; +import type { LlmParams, LlmToolDefinition } from "../../../shared/get-llm-response/types.js"; import type { Claim } from "../claims.js"; import type { LocalEntitySummary } from "./get-entity-summaries-from-text.js"; import type { @@ -38,10 +35,7 @@ const toolNames = ["submitClaims"] as const; type ToolName = (typeof toolNames)[number]; -type SubmittedClaim = Omit< - Claim, - "subjectEntityLocalId" | "claimId" | "sources" -> & { +type SubmittedClaim = Omit & { subjectEntityLocalId: EntityId | null; valueNotFound: boolean; }; @@ -66,8 +60,7 @@ const generateToolDefinitions = (params: { properties: { subjectEntityLocalId: { oneOf: [{ type: "string" }, { type: "null" }], - description: - dedent(`The localId of the subject entity of the claim. + description: dedent(`The localId of the subject entity of the claim. If you don't have a relevant subject entity, you may either omit the claim (PREFERRED), or pass 'null' here.`), }, valueNotFound: { @@ -298,9 +291,7 @@ summary: ${summary}`), Please now submit claims, remembering these key points: - Each claim MUST start with and be about one of the subject entities: ${subjectEntities .map(({ name }) => name) - .join( - ", ", - )}. If it does NOT, omit the claim or pass 'null' for the subjectEntityId + .join(", ")}. If it does NOT, omit the claim or pass 'null' for the subjectEntityId - We are particularly interested in claims related to the following properties: ${relevantProperties .map((property) => property.title) .join( @@ -393,9 +384,7 @@ export const inferEntityClaimsFromTextAgent = async (params: { retryContext, workerIdentifiers, } = params; - const subjectEntitiesStringList = subjectEntities - .map(({ name }) => name) - .join(", "); + const subjectEntitiesStringList = subjectEntities.map(({ name }) => name).join(", "); /** * Check if we should stop before proceeding with any work. @@ -407,17 +396,10 @@ export const inferEntityClaimsFromTextAgent = async (params: { return { claims: retryContext?.previousValidClaims ?? [] }; } - logger.debug( - `Inferring claims from text for entities ${subjectEntitiesStringList}`, - ); + logger.debug(`Inferring claims from text for entities ${subjectEntitiesStringList}`); - const { - createEntitiesAsDraft, - userAuthentication, - flowEntityId, - stepId, - webId, - } = await getFlowContext(); + const { createEntitiesAsDraft, userAuthentication, flowEntityId, stepId, webId } = + await getFlowContext(); const llmResponse = await getLlmResponse( { @@ -457,8 +439,7 @@ export const inferEntityClaimsFromTextAgent = async (params: { allInvalidClaims: Claim[]; retryMessages: LlmMessage[]; }) => { - const { allValidInferredClaims, allInvalidClaims, retryMessages } = - retryParams; + const { allValidInferredClaims, allInvalidClaims, retryMessages } = retryParams; const { retryCount = 0 } = retryContext ?? {}; @@ -581,12 +562,8 @@ export const inferEntityClaimsFromTextAgent = async (params: { }; const subjectEntity = - subjectEntities.find( - ({ localId }) => localId === claim.subjectEntityLocalId, - ) ?? - potentialObjectEntities.find( - ({ localId }) => localId === claim.subjectEntityLocalId, - ); + subjectEntities.find(({ localId }) => localId === claim.subjectEntityLocalId) ?? + potentialObjectEntities.find(({ localId }) => localId === claim.subjectEntityLocalId); if (!subjectEntity) { potentiallyRepeatedInvalidClaims.push({ @@ -599,12 +576,8 @@ export const inferEntityClaimsFromTextAgent = async (params: { } const objectEntity = - potentialObjectEntities.find( - ({ localId }) => localId === claim.objectEntityLocalId, - ) ?? - subjectEntities.find( - ({ localId }) => localId === claim.objectEntityLocalId, - ); + potentialObjectEntities.find(({ localId }) => localId === claim.objectEntityLocalId) ?? + subjectEntities.find(({ localId }) => localId === claim.objectEntityLocalId); if (claim.objectEntityLocalId && !objectEntity) { potentiallyRepeatedInvalidClaims.push({ @@ -616,9 +589,7 @@ export const inferEntityClaimsFromTextAgent = async (params: { continue; } - if ( - !claim.text.toLowerCase().includes(subjectEntity.name.toLowerCase()) - ) { + if (!claim.text.toLowerCase().includes(subjectEntity.name.toLowerCase())) { potentiallyRepeatedInvalidClaims.push({ ...claim, invalidReason: `The claim specifies subjectEntityId "${claim.subjectEntityLocalId}", but that entity's name "${subjectEntity.name}" does not appear in the claim. Claims must start with the name of the subject. If you described the entity slightly different, resubmit the claim beginning with "${subjectEntity.name}" instead, as long as you are sure the claim relates to this same entity. If you don't have an appropriate subject for the claim, don't include the claim. Review the subject entities in my previous message for valid subjects.`, @@ -675,25 +646,22 @@ export const inferEntityClaimsFromTextAgent = async (params: { provenance, properties: { value: { - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/": - { - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - provenance: { - sources: provenance.sources, - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/": { + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + provenance: { + sources: provenance.sources, }, - value: `${claim.text}${ - claim.prepositionalPhrases.length - ? `– ${claim.prepositionalPhrases.join(", ")}` - : "" - }`, }, + value: `${claim.text}${ + claim.prepositionalPhrases.length + ? `– ${claim.prepositionalPhrases.join(", ")}` + : "" + }`, + }, "https://hash.ai/@h/types/property-type/subject/": { metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", provenance: { sources: provenance.sources, }, @@ -736,8 +704,7 @@ export const inferEntityClaimsFromTextAgent = async (params: { /** * The LLM may submit the same valid claim across multiple retries attempting to correct invalid claims */ - (claim) => - !validClaims.some((validClaim) => validClaim.text === claim.text), + (claim) => !validClaims.some((validClaim) => validClaim.text === claim.text), ), ]; @@ -754,24 +721,23 @@ export const inferEntityClaimsFromTextAgent = async (params: { /** @todo: check if there are subject entities for which no claims have been provided */ if (invalidClaims.length > 0) { - const toolCallResponses = toolCalls.map( - (toolCall) => { - const invalidClaimsProvidedInToolCall = invalidClaims.filter( - ({ toolCallId }) => toolCallId === toolCall.id, - ); - - if (invalidClaims.length === 0) { - return { - type: "tool_result", - tool_use_id: toolCall.id, - content: "There were no invalid claims provided by this tool call.", - }; - } + const toolCallResponses = toolCalls.map((toolCall) => { + const invalidClaimsProvidedInToolCall = invalidClaims.filter( + ({ toolCallId }) => toolCallId === toolCall.id, + ); + if (invalidClaims.length === 0) { return { type: "tool_result", tool_use_id: toolCall.id, - content: dedent(` + content: "There were no invalid claims provided by this tool call.", + }; + } + + return { + type: "tool_result", + tool_use_id: toolCall.id, + content: dedent(` The following claims are invalid: ${invalidClaimsProvidedInToolCall .map( @@ -780,9 +746,7 @@ export const inferEntityClaimsFromTextAgent = async (params: { text: ${invalidClaim.text} subjectEntityId: ${invalidClaim.subjectEntityLocalId} objectEntityId: ${invalidClaim.objectEntityLocalId} - prepositionalPhrases: ${stringify( - invalidClaim.prepositionalPhrases, - )} + prepositionalPhrases: ${stringify(invalidClaim.prepositionalPhrases)} Invalid because: ${invalidClaim.invalidReason} Please correct this! @@ -792,10 +756,9 @@ export const inferEntityClaimsFromTextAgent = async (params: { You must now make another "submitClaims" tool call, correcting each of the errors identified above. `), - is_error: true, - }; - }, - ); + is_error: true, + }; + }); logger.debug( `Retrying inferring claims from text for subject entities ${subjectEntitiesStringList} with the following tool call responses: ${stringify( @@ -804,10 +767,7 @@ export const inferEntityClaimsFromTextAgent = async (params: { ); return retry({ - allInvalidClaims: [ - ...invalidClaims, - ...(retryContext?.previousInvalidClaims ?? []), - ], + allInvalidClaims: [...invalidClaims, ...(retryContext?.previousInvalidClaims ?? [])], allValidInferredClaims, retryMessages: [ llmResponse.message, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text.ai.test.ts index 5d2a94fdbcb..5175a8252a0 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-entity-claims-from-text.ai.test.ts @@ -30,18 +30,14 @@ test( const { userAuthentication } = await getFlowContext(); const dereferencedEntityTypes = await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], actorId: userAuthentication.actorId, graphApiClient, }); - const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]! - .schema; + const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]!.schema; - const url = - "https://www.londonstockexchange.com/indices/ftse-350/constituents/table" as Url; + const url = "https://www.londonstockexchange.com/indices/ftse-350/constituents/table" as Url; const webPage = await getWebPageActivity({ url, @@ -68,9 +64,7 @@ test( name: "MOLTEN VENTURES PLC ORD GBP0.01", summary: "MOLTEN VENTURES PLC is a technology investment company that invests in early-stage technology businesses.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, ], potentialObjectEntities: [], @@ -103,11 +97,9 @@ test( graphApiClient, }); - const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]! - .schema; + const dereferencedEntityType = Object.values(dereferencedEntityTypes)[0]!.schema; - const url = - "https://www.nvidia.com/de-de/geforce/graphics-cards/40-series/rtx-4090/" as Url; + const url = "https://www.nvidia.com/de-de/geforce/graphics-cards/40-series/rtx-4090/" as Url; const webPage = await getWebPageActivity({ url, @@ -133,9 +125,7 @@ test( localId: generateEntityId("6675a4ca-2282-4823-a4ff-d65d87218ebd"), name: "GeForce RTX 4090", summary: "The GeForce RTX 4090 is a high-end graphics card.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/graphics-card/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/graphics-card/v/1"], }, ], potentialObjectEntities: [], diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-summaries-then-claims-from-text.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-summaries-then-claims-from-text.ai.test.ts index 3e3ad2eb361..51eb9829efb 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-summaries-then-claims-from-text.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/infer-summaries-then-claims-from-text.ai.test.ts @@ -140,98 +140,77 @@ const _ftse350EntitySummaries: LocalEntitySummary[] = [ name: "HUNTING PLC ORD 25P", summary: "HUNTING PLC, represented by the stock code HTG, has a market cap of 614.40 million GBX, a last recorded price of 452.50 GBX, and experienced a recent price change of 80.00 GBX, translating to a 21.48% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("ef7fa92d-343a-430a-9c2b-34f8aed573d1"), name: "KELLER GROUP PLC ORD 10P", summary: "KELLER GROUP PLC, symbolized by KLR, with a market capitalization of 829.01 million GBX, a last price of 1,330.00 GBX, and a recent price jump of 194.00 GBX, which is a 17.08% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("6bb3c550-82c1-4d5f-89e9-e6723a414619"), name: "BRITVIC PLC ORD 20P", summary: "BRITVIC PLC, trading under the code BVIC, has a market capitalization of 2,288.97 million GBX, with its last price at 1,021.00 GBX, and a recent price increase of 103.50 GBX, amounting to an 11.28% rise.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("4dd0da92-40a3-40fc-84db-c75aecdd0c2d"), name: "EXPERIAN PLC ORD USD0.10", summary: "EXPERIAN PLC, designated by the code EXPN, with a market cap of 31,860.88 million GBX, a closing price of 3,697.00 GBX, and a recent gain of 227.00 GBX, equivalent to a 6.54% uplift.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("a8304ece-a8cc-4373-aa2c-6ea5b00dca2b"), name: "VODAFONE GROUP PLC ORD USD0.20 20/21", summary: "VODAFONE GROUP PLC, identified by the ticker VOD, has a market capitalization of 19,844.47 million GBX, a last recorded price of 76.72 GBX, and a recent change of 3.44 GBX, marking a 4.69% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("426fa3ef-5e9b-403e-a592-a20ec0979cdc"), name: "IMPERIAL BRANDS PLC ORD 10P", summary: "IMPERIAL BRANDS PLC, under the symbol IMB, with a market cap of 16,187.35 million GBX, a last price of 1,966.00 GBX, and a recent change of 87.50 GBX, results in a 4.66% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("85ce6362-bafa-4b08-9c19-5e2c5df020f2"), name: "CMC MARKETS PLC ORD 25P", summary: "CMC MARKETS PLC, represented by CMCX, has a market capitalization of 726.12 million GBX, recorded its last price at 271.00 GBX, and saw a recent price increase of 11.50 GBX, or 4.43%.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("73faf1ef-f64c-4308-be86-8f119db77cca"), name: "SPIRAX-SARCO ENGINEERING PLC ORD 26 12/13P", summary: "SPIRAX-SARCO ENGINEERING PLC, with the ticker SPX, boasts a market capitalization of 6,831.66 million GBX, a last price of 9,615.00 GBX, and sustained a recent increase of 355.00 GBX, amounting to a 3.83% rise.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("01c487e6-5a26-47fd-90ae-da25136b3039"), name: "REDDE NORTHGATE PLC ORD 50P", summary: "REDDE NORTHGATE PLC, trading with the code REDD, has a market capitalization of 924.94 million GBX, a last price of 420.50 GBX, and observed a recent price rise of 12.50 GBX, which is a 3.06% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("55f19188-c6ff-4eea-902b-a94b9952d917"), name: "CENTRICA PLC ORD 6 14/81P", summary: "CENTRICA PLC, identified by the ticker CNA, with a market cap of 7,410.30 million GBX, having a last recorded price of 143.40 GBX, and a recent change of 4.00 GBX, reflecting a 2.87% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, ]; test( "Test inferSummariesThenClaimsFromText with FTSE350 web page html", async () => { - const url = - "https://www.londonstockexchange.com/indices/ftse-350/constituents/table" as Url; + const url = "https://www.londonstockexchange.com/indices/ftse-350/constituents/table" as Url; const webPage = await getWebPageActivity({ url, @@ -384,162 +363,125 @@ const llmProviderExistingEntitySummaries: LocalEntitySummary[] = [ name: "GPT-4o", summary: "GPT-4o is OpenAI's most advanced multimodal large language model, known for its high efficiency, speed, and cost-effectiveness.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("771c6c67-3ea4-46e3-a120-b95a89c9ca4d"), name: "GPT-4 Turbo", summary: "GPT-4 Turbo is a high-intelligence and multimodal large language model previously favored for its advanced reasoning and vision capabilities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("bd536684-597b-4368-b390-425868dd5b83"), name: "GPT-3.5 Turbo", summary: "GPT-3.5 Turbo is a fast, inexpensive large language model optimized for simple tasks and chat functionalities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("ab049eb7-894d-42ea-a063-a76144b08b71"), name: "GPT Base", summary: "GPT Base models are large language models capable of understanding and generating natural language or code without instruction following.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("3ae3cc00-eb67-41a4-9d51-fa19e0157537"), name: "gpt-4-turbo-2024-04-09", summary: "gpt-4-turbo-2024-04-09 is a version of GPT-4 Turbo with vision capabilities, supporting JSON mode and function calling.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("c5a65ece-9499-4ebf-bf33-117b7a58c6fb"), name: "gpt-4-turbo-2024-04-09", summary: "GPT-4 Turbo with Vision is the latest GPT-4 Turbo model with vision capabilities, including support for JSON mode and function calling.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("f8aea256-2e38-4c1c-b748-c6d0be878b24"), name: "gpt-4-turbo-preview", summary: "gpt-4-turbo-preview is a preview version of GPT-4 Turbo intended to reduce incomplete task responses.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("7c5d7b76-f5c8-4dd7-a88e-7f94996050aa"), name: "gpt-4-0125-preview", summary: "gpt-4-0125-preview is an earlier preview of GPT-4 Turbo, focused on reducing inadequately completed tasks.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("14fdba17-11f2-4957-a00b-3e2e8b58a2ac"), name: "gpt-4-1106-preview", summary: "gpt-4-1106-preview is a preview version of GPT-4 Turbo with improved instruction following and new features.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("06a0bad9-da61-41c0-9149-cdbb1e49c750"), name: "gpt-4-vision-preview", summary: "gpt-4-vision-preview is a preview model of GPT-4 with image understanding and other high-level capabilities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("52aa0aa0-3753-4c03-8552-f86915fa5bfe"), name: "gpt-4-1106-vision-preview", summary: "gpt-4-1106-vision-preview is a preview model of GPT-4 with image understanding and advanced functionalities.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("d588f0d1-8ea1-4f18-b09e-099f1ba573eb"), name: "gpt-4", summary: "GPT-4 is a multimodal large language model known for its advanced reasoning, solving difficult problems with greater accuracy and broader general knowledge.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("02f58d32-6fa5-4055-8518-1178eaddabbb"), name: "gpt-4-0613", summary: "gpt-4-0613 is a snapshot model of GPT-4 focused on improved function calling support as of June 13, 2023.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("11a7b96a-44f0-48ee-9b88-19cd13bab94c"), name: "gpt-4-32k", summary: "gpt-4-32k is a version of GPT-4 designed for larger context windows, though not widely rolled out due to preference for GPT-4 Turbo.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("bf6aa6ae-85ea-4590-bf0e-6e9102cb69b0"), name: "gpt-4-32k-0613", summary: "gpt-4-32k-0613 is a snapshot model of GPT-4 for large context windows with better function calling support.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("1e42a1ef-d1ea-482e-97d2-37d4403591c6"), name: "gpt-3.5-turbo-0125", summary: "gpt-3.5-turbo-0125 is a version of GPT-3.5 Turbo with higher programming format accuracy and improved non-English language support.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("f20f5e21-17bb-4b27-9deb-9e04a89df33f"), name: "gpt-3.5-turbo-1106", - summary: - "gpt-3.5-turbo-1106 features improved instruction following and other enhancements.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + summary: "gpt-3.5-turbo-1106 features improved instruction following and other enhancements.", + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, { localId: generateEntityId("244114fe-bd85-434b-a56b-20ebefed3210"), name: "gpt-3.5-turbo-instruct", summary: "GPT-3.5 Turbo Instruct is a large language model compatible with legacy Completions endpoints.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], }, ]; @@ -562,9 +504,7 @@ test( const { userAuthentication } = await getFlowContext(); const dereferencedEntityTypes = await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/large-language-model/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/large-language-model/v/1"], actorId: userAuthentication.actorId, graphApiClient, }); diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims.ts index abb3ebd7ef3..60b6d35d7c8 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims.ts @@ -10,10 +10,7 @@ import type { ExistingEntitySummary } from "../research-entities-action/coordina import type { Claim } from "./claims.js"; import type { LocalEntitySummary } from "./infer-summaries-then-claims-from-text/get-entity-summaries-from-text.js"; import type { BaseUrl } from "@blockprotocol/type-system"; -import type { - ProposedEntity, - WorkerIdentifiers, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { ProposedEntity, WorkerIdentifiers } from "@local/hash-isomorphic-utils/flows/types"; export const proposeEntitiesFromClaims = async (params: { entitySummaries: LocalEntitySummary[]; @@ -43,9 +40,7 @@ export const proposeEntitiesFromClaims = async (params: { if (!entityType) { throw new Error( - `Could not find entity type for entity summary: ${JSON.stringify( - entitySummary, - )}`, + `Could not find entity type for entity summary: ${JSON.stringify(entitySummary)}`, ); } @@ -74,14 +69,12 @@ export const proposeEntitiesFromClaims = async (params: { _, { schema, - simplifiedPropertyTypeMappings: - outgoingLinkEntityTypeSimplifiedPropertyTypeMappings, + simplifiedPropertyTypeMappings: outgoingLinkEntityTypeSimplifiedPropertyTypeMappings, }, ]) => { return { schema, - simplifiedPropertyTypeMappings: - outgoingLinkEntityTypeSimplifiedPropertyTypeMappings, + simplifiedPropertyTypeMappings: outgoingLinkEntityTypeSimplifiedPropertyTypeMappings, }; }, ); @@ -90,14 +83,11 @@ export const proposeEntitiesFromClaims = async (params: { ...potentialLinkTargetEntitySummaries, ...(existingEntitySummaries ?? []), ].filter((potentialTargetEntitySummary) => { - const someClaimIncludesTargetEntityAsObject = - claimsWithEntityAsSubject.some((claim) => - "localId" in potentialTargetEntitySummary - ? claim.objectEntityLocalId === - potentialTargetEntitySummary.localId - : claim.objectEntityLocalId === - potentialTargetEntitySummary.entityId, - ); + const someClaimIncludesTargetEntityAsObject = claimsWithEntityAsSubject.some((claim) => + "localId" in potentialTargetEntitySummary + ? claim.objectEntityLocalId === potentialTargetEntitySummary.localId + : claim.objectEntityLocalId === potentialTargetEntitySummary.entityId, + ); const entityIsValidTarget = entityTypes .flatMap((entityType) => Object.values(entityType.schema.links ?? {})) @@ -111,9 +101,7 @@ export const proposeEntitiesFromClaims = async (params: { /** * @todo H-3363 account for parent types */ - potentialTargetEntitySummary.entityTypeIds.includes( - schema.$ref, - ), + potentialTargetEntitySummary.entityTypeIds.includes(schema.$ref), ) ); }); @@ -133,9 +121,7 @@ export const proposeEntitiesFromClaims = async (params: { isObjectOf: claimsWithEntityAsObject, isSubjectOf: claimsWithEntityAsSubject, }, - dereferencedEntityTypes: entityTypes.map( - (entityType) => entityType.schema, - ), + dereferencedEntityTypes: entityTypes.map((entityType) => entityType.schema), simplifiedPropertyTypeMappings: entityTypes.reduce( (prev, entityType) => ({ ...prev, @@ -148,24 +134,19 @@ export const proposeEntitiesFromClaims = async (params: { * target for the link. */ proposeOutgoingLinkEntityTypes: - possibleOutgoingLinkTargetEntitySummaries.length > 0 - ? possibleLinkTypesFromEntity - : [], + possibleOutgoingLinkTargetEntitySummaries.length > 0 ? possibleLinkTypesFromEntity : [], possibleOutgoingLinkTargetEntitySummaries, }); if (proposeEntityFromClaimsStatus.status !== "ok") { logger.error( - `Failed to propose entity from claims: ${stringify( - proposeEntityFromClaimsStatus, - )}`, + `Failed to propose entity from claims: ${stringify(proposeEntityFromClaimsStatus)}`, ); return []; } - const { proposedEntity, proposedOutgoingLinkEntities } = - proposeEntityFromClaimsStatus; + const { proposedEntity, proposedOutgoingLinkEntities } = proposeEntityFromClaimsStatus; return [proposedEntity, ...proposedOutgoingLinkEntities]; }), diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entities-from-claims.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entities-from-claims.ai.test.ts index 16c0742ad1e..8d89375e045 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entities-from-claims.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entities-from-claims.ai.test.ts @@ -1,10 +1,7 @@ import "../../../../shared/testing-utilities/mock-get-flow-context.js"; import { expect, test } from "vitest"; -import { - currentTimestamp, - entityIdFromComponents, -} from "@blockprotocol/type-system"; +import { currentTimestamp, entityIdFromComponents } from "@blockprotocol/type-system"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; import { getDereferencedEntityTypesActivity } from "../../../get-dereferenced-entity-types-activity.js"; @@ -34,549 +31,391 @@ const ftse350EntitySummaries: LocalEntitySummary[] = [ name: "HUNTING PLC ORD 25P", summary: "HUNTING PLC ORD 25P is a constituent of the FTSE 350 stock market index with a market cap of 614.40 million GBX and saw a recent price change of 20.94%.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("e789a5b9-890b-4a7e-960a-7b18f6abaed1"), name: "KELLER GROUP PLC ORD 10P", summary: "KELLER GROUP PLC ORD 10P is listed in the FTSE 350, having a market capitalization of 829.01 million GBX and experiencing an 18.84% price change.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("afb8f86e-ebf6-4078-9991-23f0a70983e2"), name: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P", summary: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P, part of the FTSE 350, has a market cap of 2,600.81 million GBX and a recent price change of 16.95%.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("16b1ac59-5594-4ad5-8f95-cfc279ba4381"), name: "BRITVIC PLC ORD 20P", summary: "BRITVIC PLC ORD 20P, a FTSE 350 constituent, possesses a market cap of 2,288.97 million GBX with a price change of 10.08%.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("1e1df791-6764-4c9f-9f56-519ecd116806"), name: "EXPERIAN PLC ORD USD0.10", summary: "EXPERIAN PLC ORD USD0.10, listed in the FTSE 350, has a market capitalization of 31,860.88 million GBX and a 7.90% price change.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("64844a08-e7b6-4449-8dac-df0986840c52"), name: "IMPERIAL BRANDS PLC ORD 10P", summary: "IMPERIAL BRANDS PLC ORD 10P is a FTSE 350 stock with a market cap of 16,187.35 million GBX, experiencing a 5.30% price change.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), name: "SEGRO PLC ORD 10P", summary: "SEGRO PLC ORD 10P, a FTSE 350 listed company, has a market cap of 11,996.19 million GBX and a 5.09% change in price.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("c5cb0cff-487f-4805-b58f-84404e382c50"), name: "IP GROUP PLC ORD 2P", summary: "IP GROUP PLC ORD 2P, included in the FTSE 350, has a market capitalization of 522.51 million GBX and a 4.54% change in price.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("a271bdf9-9be2-49e3-b987-6616e32d571c"), name: "VODAFONE GROUP PLC ORD USD0.20 20/21", summary: "VODAFONE GROUP PLC ORD USD0.20 20/21 is part of the FTSE 350 with a market cap of 19,844.47 million GBX and a 4.01% price change.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("86737639-f13a-45dd-a312-1d7a4e7e1b1e"), name: "REDDE NORTHGATE PLC ORD 50P", summary: "REDDE NORTHGATE PLC ORD 50P, a constituent of the FTSE 350, has a market cap of 924.94 million GBX and a 3.92% change in price.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }, { localId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), name: "FTSE 350", summary: "A stock market index comprised of 350 high-capitalisation companies listed on the London Stock Exchange.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-index/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-index/v/1"], }, ]; const ftse350Claims = [ { text: "HUNTING PLC ORD 25P has the code HTG", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), prepositionalPhrases: [], }, { text: "HUNTING PLC ORD 25P has the name HUNTING PLC ORD 25P", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), prepositionalPhrases: [], }, { text: "HUNTING PLC ORD 25P uses the currency GBX", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), prepositionalPhrases: [], }, { text: "HUNTING PLC ORD 25P has a market capitalization of 614.40 million", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), prepositionalPhrases: [], }, { text: "HUNTING PLC ORD 25P has a price of 450.50 GBX", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), prepositionalPhrases: [], }, { text: "HUNTING PLC ORD 25P has a change of 78.00 GBX", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), prepositionalPhrases: [], }, { text: "HUNTING PLC ORD 25P has a change percentage of 20.94%", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), prepositionalPhrases: [], }, { text: "HUNTING PLC ORD 25P appears in the index FTSE 350", - subjectEntityLocalId: generateEntityId( - "91f82ccc-42b0-4dd1-8b53-56e07eb265b2", - ), - objectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("91f82ccc-42b0-4dd1-8b53-56e07eb265b2"), + objectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "KELLER GROUP PLC ORD 10P's currency is GBX", - subjectEntityLocalId: generateEntityId( - "e789a5b9-890b-4a7e-960a-7b18f6abaed1", - ), + subjectEntityLocalId: generateEntityId("e789a5b9-890b-4a7e-960a-7b18f6abaed1"), prepositionalPhrases: [], }, { text: "KELLER GROUP PLC ORD 10P's market capitalization is 829.01 million", - subjectEntityLocalId: generateEntityId( - "e789a5b9-890b-4a7e-960a-7b18f6abaed1", - ), + subjectEntityLocalId: generateEntityId("e789a5b9-890b-4a7e-960a-7b18f6abaed1"), prepositionalPhrases: [], }, { text: "KELLER GROUP PLC ORD 10P's price is 1,350.00", - subjectEntityLocalId: generateEntityId( - "e789a5b9-890b-4a7e-960a-7b18f6abaed1", - ), + subjectEntityLocalId: generateEntityId("e789a5b9-890b-4a7e-960a-7b18f6abaed1"), prepositionalPhrases: [], }, { text: "KELLER GROUP PLC ORD 10P's change is 214.00", - subjectEntityLocalId: generateEntityId( - "e789a5b9-890b-4a7e-960a-7b18f6abaed1", - ), + subjectEntityLocalId: generateEntityId("e789a5b9-890b-4a7e-960a-7b18f6abaed1"), prepositionalPhrases: [], }, { text: "KELLER GROUP PLC ORD 10P's change percentage is 18.84%", - subjectEntityLocalId: generateEntityId( - "e789a5b9-890b-4a7e-960a-7b18f6abaed1", - ), + subjectEntityLocalId: generateEntityId("e789a5b9-890b-4a7e-960a-7b18f6abaed1"), prepositionalPhrases: [], }, { text: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P is listed on the GBX", - subjectEntityLocalId: generateEntityId( - "afb8f86e-ebf6-4078-9991-23f0a70983e2", - ), + subjectEntityLocalId: generateEntityId("afb8f86e-ebf6-4078-9991-23f0a70983e2"), prepositionalPhrases: [], }, { text: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P has a market capitalization of 2,600.81 million", - subjectEntityLocalId: generateEntityId( - "afb8f86e-ebf6-4078-9991-23f0a70983e2", - ), + subjectEntityLocalId: generateEntityId("afb8f86e-ebf6-4078-9991-23f0a70983e2"), prepositionalPhrases: [], }, { text: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P has a price of 317.40 GBX", - subjectEntityLocalId: generateEntityId( - "afb8f86e-ebf6-4078-9991-23f0a70983e2", - ), + subjectEntityLocalId: generateEntityId("afb8f86e-ebf6-4078-9991-23f0a70983e2"), prepositionalPhrases: [], }, { text: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P has an increase of 46 GBX", - subjectEntityLocalId: generateEntityId( - "afb8f86e-ebf6-4078-9991-23f0a70983e2", - ), + subjectEntityLocalId: generateEntityId("afb8f86e-ebf6-4078-9991-23f0a70983e2"), prepositionalPhrases: [], }, { text: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P has an increase of 16.95%", - subjectEntityLocalId: generateEntityId( - "afb8f86e-ebf6-4078-9991-23f0a70983e2", - ), + subjectEntityLocalId: generateEntityId("afb8f86e-ebf6-4078-9991-23f0a70983e2"), prepositionalPhrases: [], }, { text: "INTERNATIONAL DISTRIBUTIONS SERVICE ORD 1P appears in FTSE 350", - subjectEntityLocalId: generateEntityId( - "afb8f86e-ebf6-4078-9991-23f0a70983e2", - ), - objectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("afb8f86e-ebf6-4078-9991-23f0a70983e2"), + objectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "BRITVIC PLC ORD 20P has a market capitalization of 2288.97 million GBP", - subjectEntityLocalId: generateEntityId( - "16b1ac59-5594-4ad5-8f95-cfc279ba4381", - ), + subjectEntityLocalId: generateEntityId("16b1ac59-5594-4ad5-8f95-cfc279ba4381"), prepositionalPhrases: ["as of the last update"], }, { text: "BRITVIC PLC ORD 20P has a price of 1010 GBX", - subjectEntityLocalId: generateEntityId( - "16b1ac59-5594-4ad5-8f95-cfc279ba4381", - ), + subjectEntityLocalId: generateEntityId("16b1ac59-5594-4ad5-8f95-cfc279ba4381"), prepositionalPhrases: ["as of the last update"], }, { text: "BRITVIC PLC ORD 20P has a change of 92.50 GBX", - subjectEntityLocalId: generateEntityId( - "16b1ac59-5594-4ad5-8f95-cfc279ba4381", - ), + subjectEntityLocalId: generateEntityId("16b1ac59-5594-4ad5-8f95-cfc279ba4381"), prepositionalPhrases: ["as of the last update"], }, { text: "BRITVIC PLC ORD 20P has a change percentage of 10.08%", - subjectEntityLocalId: generateEntityId( - "16b1ac59-5594-4ad5-8f95-cfc279ba4381", - ), + subjectEntityLocalId: generateEntityId("16b1ac59-5594-4ad5-8f95-cfc279ba4381"), prepositionalPhrases: ["as of the last update"], }, { text: "BRITVIC PLC ORD 20P appears in FTSE 350", - subjectEntityLocalId: generateEntityId( - "16b1ac59-5594-4ad5-8f95-cfc279ba4381", - ), - objectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("16b1ac59-5594-4ad5-8f95-cfc279ba4381"), + objectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "EXPERIAN PLC ORD USD0.10 has a market capitalization of 31,860.88 million GBX", - subjectEntityLocalId: generateEntityId( - "1e1df791-6764-4c9f-9f56-519ecd116806", - ), + subjectEntityLocalId: generateEntityId("1e1df791-6764-4c9f-9f56-519ecd116806"), prepositionalPhrases: [], }, { text: "EXPERIAN PLC ORD USD0.10 has a price of 3,744.00 GBX", - subjectEntityLocalId: generateEntityId( - "1e1df791-6764-4c9f-9f56-519ecd116806", - ), + subjectEntityLocalId: generateEntityId("1e1df791-6764-4c9f-9f56-519ecd116806"), prepositionalPhrases: [], }, { text: "EXPERIAN PLC ORD USD0.10 has a change of 274.00 GBX", - subjectEntityLocalId: generateEntityId( - "1e1df791-6764-4c9f-9f56-519ecd116806", - ), + subjectEntityLocalId: generateEntityId("1e1df791-6764-4c9f-9f56-519ecd116806"), prepositionalPhrases: [], }, { text: "EXPERIAN PLC ORD USD0.10 has a change percentage of 7.90%", - subjectEntityLocalId: generateEntityId( - "1e1df791-6764-4c9f-9f56-519ecd116806", - ), + subjectEntityLocalId: generateEntityId("1e1df791-6764-4c9f-9f56-519ecd116806"), prepositionalPhrases: [], }, { text: "IMPERIAL BRANDS PLC ORD 10P is denominated in GBX", - subjectEntityLocalId: generateEntityId( - "64844a08-e7b6-4449-8dac-df0986840c52", - ), + subjectEntityLocalId: generateEntityId("64844a08-e7b6-4449-8dac-df0986840c52"), prepositionalPhrases: [], }, { text: "IMPERIAL BRANDS PLC ORD 10P has a market capitalization of 16187.35 million", - subjectEntityLocalId: generateEntityId( - "64844a08-e7b6-4449-8dac-df0986840c52", - ), + subjectEntityLocalId: generateEntityId("64844a08-e7b6-4449-8dac-df0986840c52"), prepositionalPhrases: [], }, { text: "IMPERIAL BRANDS PLC ORD 10P has a price of 1978.00 GBX", - subjectEntityLocalId: generateEntityId( - "64844a08-e7b6-4449-8dac-df0986840c52", - ), + subjectEntityLocalId: generateEntityId("64844a08-e7b6-4449-8dac-df0986840c52"), prepositionalPhrases: [], }, { text: "IMPERIAL BRANDS PLC ORD 10P has a change of 99.50 GBX", - subjectEntityLocalId: generateEntityId( - "64844a08-e7b6-4449-8dac-df0986840c52", - ), + subjectEntityLocalId: generateEntityId("64844a08-e7b6-4449-8dac-df0986840c52"), prepositionalPhrases: [], }, { text: "IMPERIAL BRANDS PLC ORD 10P has a change percentage of 5.30%", - subjectEntityLocalId: generateEntityId( - "64844a08-e7b6-4449-8dac-df0986840c52", - ), + subjectEntityLocalId: generateEntityId("64844a08-e7b6-4449-8dac-df0986840c52"), prepositionalPhrases: [], }, { text: "SEGRO PLC ORD 10P has the code SGRO", - subjectEntityLocalId: generateEntityId( - "3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68", - ), + subjectEntityLocalId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), prepositionalPhrases: [], }, { text: "SEGRO PLC ORD 10P has the currency GBX", - subjectEntityLocalId: generateEntityId( - "3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68", - ), + subjectEntityLocalId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), prepositionalPhrases: [], }, { text: "SEGRO PLC ORD 10P has a market capitalization of 11996.19 million", - subjectEntityLocalId: generateEntityId( - "3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68", - ), + subjectEntityLocalId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), prepositionalPhrases: [], }, { text: "SEGRO PLC ORD 10P has a price of 933.00 GBX", - subjectEntityLocalId: generateEntityId( - "3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68", - ), + subjectEntityLocalId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), prepositionalPhrases: [], }, { text: "SEGRO PLC ORD 10P has a change of 45.20", - subjectEntityLocalId: generateEntityId( - "3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68", - ), + subjectEntityLocalId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), prepositionalPhrases: [], }, { text: "SEGRO PLC ORD 10P has a change percentage of 5.09%", - subjectEntityLocalId: generateEntityId( - "3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68", - ), + subjectEntityLocalId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), prepositionalPhrases: [], }, { text: "SEGRO PLC ORD 10P appears in the index FTSE 350", - subjectEntityLocalId: generateEntityId( - "3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68", - ), - objectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("3b5eff7f-46a5-4c2b-b1f7-7b01fb957e68"), + objectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "IP GROUP PLC ORD 2P has a market cap of 522.51 million GBP", - subjectEntityLocalId: generateEntityId( - "c5cb0cff-487f-4805-b58f-84404e382c50", - ), + subjectEntityLocalId: generateEntityId("c5cb0cff-487f-4805-b58f-84404e382c50"), prepositionalPhrases: [], }, { text: "IP GROUP PLC ORD 2P has a price of 53.00 GBX", - subjectEntityLocalId: generateEntityId( - "c5cb0cff-487f-4805-b58f-84404e382c50", - ), + subjectEntityLocalId: generateEntityId("c5cb0cff-487f-4805-b58f-84404e382c50"), prepositionalPhrases: [], }, { text: "IP GROUP PLC ORD 2P has a change of 2.30 GBX", - subjectEntityLocalId: generateEntityId( - "c5cb0cff-487f-4805-b58f-84404e382c50", - ), + subjectEntityLocalId: generateEntityId("c5cb0cff-487f-4805-b58f-84404e382c50"), prepositionalPhrases: [], }, { text: "IP GROUP PLC ORD 2P has a change percentage of 4.54%", - subjectEntityLocalId: generateEntityId( - "c5cb0cff-487f-4805-b58f-84404e382c50", - ), + subjectEntityLocalId: generateEntityId("c5cb0cff-487f-4805-b58f-84404e382c50"), prepositionalPhrases: [], }, { text: "IP GROUP PLC ORD 2P appears in FTSE 350", - subjectEntityLocalId: generateEntityId( - "c5cb0cff-487f-4805-b58f-84404e382c50", - ), - objectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("c5cb0cff-487f-4805-b58f-84404e382c50"), + objectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "VODAFONE GROUP PLC ORD USD0.20 20/21 has a market capitalization of 19844.47 million", - subjectEntityLocalId: generateEntityId( - "a271bdf9-9be2-49e3-b987-6616e32d571c", - ), + subjectEntityLocalId: generateEntityId("a271bdf9-9be2-49e3-b987-6616e32d571c"), prepositionalPhrases: [], }, { text: "VODAFONE GROUP PLC ORD USD0.20 20/21 is denominated in GBX", - subjectEntityLocalId: generateEntityId( - "a271bdf9-9be2-49e3-b987-6616e32d571c", - ), + subjectEntityLocalId: generateEntityId("a271bdf9-9be2-49e3-b987-6616e32d571c"), prepositionalPhrases: [], }, { text: "VODAFONE GROUP PLC ORD USD0.20 20/21 has a price of 76.22 GBX", - subjectEntityLocalId: generateEntityId( - "a271bdf9-9be2-49e3-b987-6616e32d571c", - ), + subjectEntityLocalId: generateEntityId("a271bdf9-9be2-49e3-b987-6616e32d571c"), prepositionalPhrases: [], }, { text: "VODAFONE GROUP PLC ORD USD0.20 20/21 appears in index FTSE 350", - subjectEntityLocalId: generateEntityId( - "a271bdf9-9be2-49e3-b987-6616e32d571c", - ), - objectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("a271bdf9-9be2-49e3-b987-6616e32d571c"), + objectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "REDDE NORTHGATE PLC ORD 50P has a currency of GBX", - subjectEntityLocalId: generateEntityId( - "86737639-f13a-45dd-a312-1d7a4e7e1b1e", - ), + subjectEntityLocalId: generateEntityId("86737639-f13a-45dd-a312-1d7a4e7e1b1e"), prepositionalPhrases: [], }, { text: "REDDE NORTHGATE PLC ORD 50P has a market capitalization of 924.94 million", - subjectEntityLocalId: generateEntityId( - "86737639-f13a-45dd-a312-1d7a4e7e1b1e", - ), + subjectEntityLocalId: generateEntityId("86737639-f13a-45dd-a312-1d7a4e7e1b1e"), prepositionalPhrases: [], }, { text: "REDDE NORTHGATE PLC ORD 50P has a price of 424.00 GBX", - subjectEntityLocalId: generateEntityId( - "86737639-f13a-45dd-a312-1d7a4e7e1b1e", - ), + subjectEntityLocalId: generateEntityId("86737639-f13a-45dd-a312-1d7a4e7e1b1e"), prepositionalPhrases: [], }, { text: "REDDE NORTHGATE PLC ORD 50P had a change of 16.00 GBX", - subjectEntityLocalId: generateEntityId( - "86737639-f13a-45dd-a312-1d7a4e7e1b1e", - ), + subjectEntityLocalId: generateEntityId("86737639-f13a-45dd-a312-1d7a4e7e1b1e"), prepositionalPhrases: [], }, { text: "REDDE NORTHGATE PLC ORD 50P had a change percentage of 3.92%", - subjectEntityLocalId: generateEntityId( - "86737639-f13a-45dd-a312-1d7a4e7e1b1e", - ), + subjectEntityLocalId: generateEntityId("86737639-f13a-45dd-a312-1d7a4e7e1b1e"), prepositionalPhrases: [], }, { text: "REDDE NORTHGATE PLC ORD 50P appears in index FTSE 350", - subjectEntityLocalId: generateEntityId( - "86737639-f13a-45dd-a312-1d7a4e7e1b1e", - ), - objectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("86737639-f13a-45dd-a312-1d7a4e7e1b1e"), + objectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "FTSE 350 has constituents", - subjectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "FTSE 350 constituents are reviewed every quarter", - subjectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "FTSE 350 review months include March", - subjectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "FTSE 350 review months include June", - subjectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "FTSE 350 review months include September", - subjectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, { text: "FTSE 350 review months include December", - subjectEntityLocalId: generateEntityId( - "c1008286-64e8-49de-b86d-0360630a81c7", - ), + subjectEntityLocalId: generateEntityId("c1008286-64e8-49de-b86d-0360630a81c7"), prepositionalPhrases: [], }, ]; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims-agent.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims-agent.ts index f6a9906eb5b..19bd2d84f7f 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims-agent.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims-agent.ts @@ -1,13 +1,7 @@ import dedent from "dedent"; -import { - entityIdFromComponents, - mustHaveAtLeastOne, -} from "@blockprotocol/type-system"; -import { - HashEntity, - mergePropertyObjectAndMetadata, -} from "@local/hash-graph-sdk/entity"; +import { entityIdFromComponents, mustHaveAtLeastOne } from "@blockprotocol/type-system"; +import { HashEntity, mergePropertyObjectAndMetadata } from "@local/hash-graph-sdk/entity"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; import { extractErrorMessage } from "../../../infer-entities/shared/extract-validation-failure-details.js"; @@ -21,10 +15,7 @@ import { stringify } from "../../../shared/stringify.js"; import type { PropertyValueWithSimplifiedProperties } from "../../../infer-entities/shared/map-simplified-properties-to-properties.js"; import type { DereferencedEntityType } from "../../../shared/dereference-entity-type.js"; -import type { - LlmMessage, - LlmUserMessage, -} from "../../../shared/get-llm-response/llm-message.js"; +import type { LlmMessage, LlmUserMessage } from "../../../shared/get-llm-response/llm-message.js"; import type { LlmToolDefinition } from "../../../shared/get-llm-response/types.js"; import type { ExistingEntitySummary } from "../../research-entities-action/coordinating-agent/summarize-existing-entities.js"; import type { Claim } from "../claims.js"; @@ -117,10 +108,9 @@ const generatePropertyMetadata = (params: { value: {}, }; - for (const [ - simplifiedPropertyKey, - { claimIdsUsedToDetermineValue }, - ] of Object.entries(inputProperties)) { + for (const [simplifiedPropertyKey, { claimIdsUsedToDetermineValue }] of Object.entries( + inputProperties, + )) { const claimsUsedToDetermineValue = allClaims.filter((claim) => claimIdsUsedToDetermineValue.includes(claim.claimId), ); @@ -167,10 +157,7 @@ const generatePropertyMetadata = (params: { } return { - propertyMetadata: - Object.keys(propertyMetadata).length > 0 - ? propertyMetadata - : { value: {} }, + propertyMetadata: Object.keys(propertyMetadata).length > 0 ? propertyMetadata : { value: {} }, }; }; @@ -221,31 +208,23 @@ const generateToolDefinitions = (params: { entityTypeId: { type: "string", enum: [dereferencedOutgoingLinkEntityType.$id], - description: - "The entity type ID of the target entity", + description: "The entity type ID of the target entity", }, targetEntityId: { type: "string", description: "The ID of the target entity", }, properties: { - description: - "The properties to set on the outgoing link", + description: "The properties to set on the outgoing link", default: {}, type: "object", additionalProperties: false, - properties: - mapPropertiesSchemaToInputPropertiesSchema({ - properties: - dereferencedOutgoingLinkEntityType.properties, - }), + properties: mapPropertiesSchemaToInputPropertiesSchema({ + properties: dereferencedOutgoingLinkEntityType.properties, + }), }, }, - required: [ - "entityTypeId", - "targetEntityId", - "properties", - ], + required: ["entityTypeId", "targetEntityId", "properties"], }), ), }, @@ -255,9 +234,7 @@ const generateToolDefinitions = (params: { }, required: [ "properties", - ...(proposeOutgoingLinkEntityTypes.length > 0 - ? ["outgoingLinks"] - : []), + ...(proposeOutgoingLinkEntityTypes.length > 0 ? ["outgoingLinks"] : []), ], }, }, @@ -315,10 +292,7 @@ export const proposeEntityFromClaimsAgent = async (params: { schema: DereferencedEntityType; simplifiedPropertyTypeMappings: Record; }[]; - possibleOutgoingLinkTargetEntitySummaries: ( - | LocalEntitySummary - | ExistingEntitySummary - )[]; + possibleOutgoingLinkTargetEntitySummaries: (LocalEntitySummary | ExistingEntitySummary)[]; retryContext?: { retryCount: number; retryMessages: LlmMessage[]; @@ -349,8 +323,7 @@ export const proposeEntityFromClaimsAgent = async (params: { const allClaims = [...claims.isObjectOf, ...claims.isSubjectOf]; - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const proposingOutgoingLinks = proposeOutgoingLinkEntityTypes.length > 0 && @@ -407,9 +380,7 @@ export const proposeEntityFromClaimsAgent = async (params: { ); if (llmResponse.status !== "ok") { - throw new Error( - `Failed to get response from LLM: ${stringify(llmResponse)}`, - ); + throw new Error(`Failed to get response from LLM: ${stringify(llmResponse)}`); } const retry = (retryParams: { retryMessage: LlmUserMessage }) => { @@ -448,20 +419,17 @@ export const proposeEntityFromClaimsAgent = async (params: { }); } - const proposeEntityToolCall = toolCalls.find( - (toolCall) => toolCall.name === "proposeEntity", - ); + const proposeEntityToolCall = toolCalls.find((toolCall) => toolCall.name === "proposeEntity"); if (proposeEntityToolCall) { - const { properties: inputProperties, outgoingLinks } = - proposeEntityToolCall.input as { - properties?: InputPropertiesObject; - outgoingLinks?: { - entityTypeId: string; - targetEntityId: string; - properties: InputPropertiesObject; - }[]; - }; + const { properties: inputProperties, outgoingLinks } = proposeEntityToolCall.input as { + properties?: InputPropertiesObject; + outgoingLinks?: { + entityTypeId: string; + targetEntityId: string; + properties: InputPropertiesObject; + }[]; + }; if (!inputProperties) { return retry({ @@ -507,10 +475,7 @@ export const proposeEntityFromClaimsAgent = async (params: { /** @todo: set this depending on whether entities are created as drafts? */ requiredProperties: false, }, - properties: mergePropertyObjectAndMetadata( - properties, - propertyMetadata, - ), + properties: mergePropertyObjectAndMetadata(properties, propertyMetadata), }); } catch (error) { const invalidReason = `${extractErrorMessage(error)}.`; @@ -536,8 +501,7 @@ export const proposeEntityFromClaimsAgent = async (params: { outgoingLinks.map(async (outgoingLink) => { const { schema: dereferencedOutgoingLinkEntityType, - simplifiedPropertyTypeMappings: - outgoingLinkSimplifiedPropertyTypeMappings, + simplifiedPropertyTypeMappings: outgoingLinkSimplifiedPropertyTypeMappings, } = proposeOutgoingLinkEntityTypes.find( ({ schema }) => schema.$id === outgoingLink.entityTypeId, @@ -557,24 +521,20 @@ export const proposeEntityFromClaimsAgent = async (params: { const outgoingLinkInputProperties = outgoingLink.properties; - const outgoingLinkSimplifiedProperties = - mapInputPropertiesToPropertiesObject({ - inputProperties: outgoingLinkInputProperties, - }); + const outgoingLinkSimplifiedProperties = mapInputPropertiesToPropertiesObject({ + inputProperties: outgoingLinkInputProperties, + }); const outgoingLinkProperties = mapSimplifiedPropertiesToProperties({ simplifiedProperties: outgoingLinkSimplifiedProperties, - simplifiedPropertyTypeMappings: - outgoingLinkSimplifiedPropertyTypeMappings, + simplifiedPropertyTypeMappings: outgoingLinkSimplifiedPropertyTypeMappings, }); - const { propertyMetadata: outgoingLinkPropertyMetadata } = - generatePropertyMetadata({ - inputProperties: outgoingLinkInputProperties, - allClaims, - simplifiedPropertyTypeMappings: - outgoingLinkSimplifiedPropertyTypeMappings, - }); + const { propertyMetadata: outgoingLinkPropertyMetadata } = generatePropertyMetadata({ + inputProperties: outgoingLinkInputProperties, + allClaims, + simplifiedPropertyTypeMappings: outgoingLinkSimplifiedPropertyTypeMappings, + }); const claimsUsedToToCreateLink = allClaims.filter((claim) => Object.values(outgoingLink.properties) @@ -604,15 +564,12 @@ export const proposeEntityFromClaimsAgent = async (params: { ); } - const targetEntitySummary = - possibleOutgoingLinkTargetEntitySummaries.find( - (possibleOutgoingLinkTargetEntitySummary) => - "localId" in possibleOutgoingLinkTargetEntitySummary - ? possibleOutgoingLinkTargetEntitySummary.localId === - outgoingLink.targetEntityId - : possibleOutgoingLinkTargetEntitySummary.entityId === - outgoingLink.targetEntityId, - ); + const targetEntitySummary = possibleOutgoingLinkTargetEntitySummaries.find( + (possibleOutgoingLinkTargetEntitySummary) => + "localId" in possibleOutgoingLinkTargetEntitySummary + ? possibleOutgoingLinkTargetEntitySummary.localId === outgoingLink.targetEntityId + : possibleOutgoingLinkTargetEntitySummary.entityId === outgoingLink.targetEntityId, + ); if (!targetEntitySummary) { retryToolCallMessages.push( @@ -633,15 +590,10 @@ export const proposeEntityFromClaimsAgent = async (params: { * 2. Or/additionally introduce a 'has predicate' relationship from the claim, * which we either use always or ask an LLM to decide between subject/object/predicate based on the phrasing of the claim. */ - isObjectOf: claimsUsedToToCreateLink.map( - (claim) => claim.claimId, - ), + isObjectOf: claimsUsedToToCreateLink.map((claim) => claim.claimId), isSubjectOf: [], }, - localEntityId: entityIdFromComponents( - webId, - generateUuid() as EntityUuid, - ), + localEntityId: entityIdFromComponents(webId, generateUuid() as EntityUuid), summary: `"${dereferencedOutgoingLinkEntityType.title}" link with source ${entitySummary.name} and target ${targetEntitySummary.name}`, sourceEntityId: { kind: "proposed-entity", @@ -694,9 +646,7 @@ export const proposeEntityFromClaimsAgent = async (params: { localEntityId: entitySummary.localId, propertyMetadata, summary: entitySummary.summary, - entityTypeIds: mustHaveAtLeastOne( - dereferencedEntityTypes.map((type) => type.$id), - ), + entityTypeIds: mustHaveAtLeastOne(dereferencedEntityTypes.map((type) => type.$id)), properties, provenance: editionProvenance, }; @@ -708,9 +658,7 @@ export const proposeEntityFromClaimsAgent = async (params: { }; } - const abandonEntityToolCall = toolCalls.find( - (toolCall) => toolCall.name === "abandonEntity", - ); + const abandonEntityToolCall = toolCalls.find((toolCall) => toolCall.name === "abandonEntity"); if (abandonEntityToolCall) { const { explanation } = abandonEntityToolCall.input as { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims.ai.test.ts index 069ae625b49..642824b7868 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/shared/propose-entities-from-claims/propose-entity-from-claims.ai.test.ts @@ -1,10 +1,7 @@ import "../../../../shared/testing-utilities/mock-get-flow-context.js"; import { expect, test } from "vitest"; -import { - currentTimestamp, - entityIdFromComponents, -} from "@blockprotocol/type-system"; +import { currentTimestamp, entityIdFromComponents } from "@blockprotocol/type-system"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; import { getDereferencedEntityTypesActivity } from "../../../get-dereferenced-entity-types-activity.js"; @@ -14,12 +11,7 @@ import { proposeEntityFromClaimsAgent } from "./propose-entity-from-claims-agent import type { Claim } from "../claims.js"; import type { LocalEntitySummary } from "../infer-summaries-then-claims-from-text/get-entity-summaries-from-text.js"; -import type { - EntityUuid, - Timestamp, - Url, - WebId, -} from "@blockprotocol/type-system"; +import type { EntityUuid, Timestamp, Url, WebId } from "@blockprotocol/type-system"; /** * @file These are not 'tests' but rather ways of running specific agents, @@ -38,38 +30,28 @@ const huntingPlcEntitySummary: LocalEntitySummary = { name: "HUNTING PLC ORD 25P", summary: "HUNTING PLC, represented by the stock code HTG, has a market cap of 614.40 million GBX, a last recorded price of 452.50 GBX, and experienced a recent price change of 80.00 GBX, translating to a 21.48% increase.", - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], }; const huntingPlcEntityClaims = [ { text: "HUNTING PLC has a market cap of 614.40 million GBX", - subjectEntityLocalId: generateEntityId( - "66f93842-c6e0-4378-ab04-519edd7231af", - ), + subjectEntityLocalId: generateEntityId("66f93842-c6e0-4378-ab04-519edd7231af"), prepositionalPhrases: [], }, { text: "HUNTING PLC has a price of 443.50 GBX", - subjectEntityLocalId: generateEntityId( - "66f93842-c6e0-4378-ab04-519edd7231af", - ), + subjectEntityLocalId: generateEntityId("66f93842-c6e0-4378-ab04-519edd7231af"), prepositionalPhrases: [], }, { text: "HUNTING PLC has a change value of 71.00 GBX", - subjectEntityLocalId: generateEntityId( - "66f93842-c6e0-4378-ab04-519edd7231af", - ), + subjectEntityLocalId: generateEntityId("66f93842-c6e0-4378-ab04-519edd7231af"), prepositionalPhrases: [], }, { text: "HUNTING PLC has a change percentage of 19.06%", - subjectEntityLocalId: generateEntityId( - "66f93842-c6e0-4378-ab04-519edd7231af", - ), + subjectEntityLocalId: generateEntityId("66f93842-c6e0-4378-ab04-519edd7231af"), prepositionalPhrases: [], }, ]; @@ -80,9 +62,7 @@ test( const { userAuthentication } = await getFlowContext(); const dereferencedEntityTypes = await getDereferencedEntityTypesActivity({ - entityTypeIds: [ - "https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1", - ], + entityTypeIds: ["https://hash.ai/@h/types/entity-type/stock-market-constituent/v/1"], actorId: userAuthentication.actorId, graphApiClient, }); @@ -140,9 +120,7 @@ const claimsAboutGraphicsCard: Claim[] = [ { claimId: generateEntityId("5294b951-fbe0-4b31-b287-130036c1f551"), text: "NVIDIA GeForce RTX 2080 Ti provides 11GB of memory", - subjectEntityLocalId: generateEntityId( - "d705527d-59ed-462c-92c4-507b92095c22", - ), + subjectEntityLocalId: generateEntityId("d705527d-59ed-462c-92c4-507b92095c22"), prepositionalPhrases: [], sources: [ { @@ -157,9 +135,7 @@ const claimsAboutGraphicsCard: Claim[] = [ { claimId: generateEntityId("e2ef33ee-d23e-4fba-aded-944067013515"), text: "NVIDIA GeForce RTX 2080 Ti has a 352-bit memory bus", - subjectEntityLocalId: generateEntityId( - "d705527d-59ed-462c-92c4-507b92095c22", - ), + subjectEntityLocalId: generateEntityId("d705527d-59ed-462c-92c4-507b92095c22"), prepositionalPhrases: [], sources: [ { @@ -174,9 +150,7 @@ const claimsAboutGraphicsCard: Claim[] = [ { claimId: generateEntityId("710c911e-7641-4f7a-908e-dd5d162399d5"), text: "NVIDIA GeForce RTX 2080 Ti has a 6MB cache", - subjectEntityLocalId: generateEntityId( - "d705527d-59ed-462c-92c4-507b92095c22", - ), + subjectEntityLocalId: generateEntityId("d705527d-59ed-462c-92c4-507b92095c22"), prepositionalPhrases: [], sources: [ { @@ -191,9 +165,7 @@ const claimsAboutGraphicsCard: Claim[] = [ { claimId: generateEntityId("b8547d6c-dbdc-4765-8e40-326c39b87e6c"), text: "NVIDIA GeForce RTX 2080 Ti provides roughly 120 teraflops of performance", - subjectEntityLocalId: generateEntityId( - "d705527d-59ed-462c-92c4-507b92095c22", - ), + subjectEntityLocalId: generateEntityId("d705527d-59ed-462c-92c4-507b92095c22"), prepositionalPhrases: [], sources: [ { @@ -208,9 +180,7 @@ const claimsAboutGraphicsCard: Claim[] = [ { claimId: generateEntityId("06e3ae80-e7c7-4762-877b-36241edf8b55"), text: "NVIDIA GeForce RTX 2080 Ti is a PC GPU", - subjectEntityLocalId: generateEntityId( - "d705527d-59ed-462c-92c4-507b92095c22", - ), + subjectEntityLocalId: generateEntityId("d705527d-59ed-462c-92c4-507b92095c22"), prepositionalPhrases: [], sources: [ { @@ -225,9 +195,7 @@ const claimsAboutGraphicsCard: Claim[] = [ { claimId: generateEntityId("e9fa4dba-a4d0-421d-b907-7b534fb0eae0"), text: "NVIDIA GeForce RTX 2080 Ti is based on the TU102 graphics processor", - subjectEntityLocalId: generateEntityId( - "d705527d-59ed-462c-92c4-507b92095c22", - ), + subjectEntityLocalId: generateEntityId("d705527d-59ed-462c-92c4-507b92095c22"), prepositionalPhrases: [], sources: [ { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/web-search-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/web-search-action.ts index 2fcb5649dcf..f9eee208ceb 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/web-search-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/web-search-action.ts @@ -20,13 +20,9 @@ export type GetWebSearchResultsResponse = Omit< const mapWebSearchResults = ( webSearchResults: GetWebSearchResults200ResponseWebSearchResultsInner[], ): GetWebSearchResultsResponse[] => - webSearchResults.map( - (webSearchResult) => webSearchResult as GetWebSearchResultsResponse, - ); + webSearchResults.map((webSearchResult) => webSearchResult as GetWebSearchResultsResponse); -export const webSearchAction: AiFlowActionActivity<"webSearch"> = async ({ - inputs, -}) => { +export const webSearchAction: AiFlowActionActivity<"webSearch"> = async ({ inputs }) => { const { query, numberOfSearchResults } = getSimplifiedAiFlowActionInputs({ inputs, actionType: "webSearch", diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action.ts index cc1186273e1..0b92b855130 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action.ts @@ -31,10 +31,7 @@ import { convertSubgraphToSheetRequests } from "./write-google-sheet-action/conv import { getFilterFromBlockProtocolQueryEntity } from "./write-google-sheet-action/get-filter-from-bp-query-entity.js"; import { getSubgraphFromFilter } from "./write-google-sheet-action/get-subgraph-from-filter.js"; -import type { - OriginProvenance, - ProvidedEntityEditionProvenance, -} from "@blockprotocol/type-system"; +import type { OriginProvenance, ProvidedEntityEditionProvenance } from "@blockprotocol/type-system"; import type { AiFlowActionActivity } from "@local/hash-backend-utils/flows"; import type { VaultClient } from "@local/hash-backend-utils/vault"; import type { @@ -87,14 +84,12 @@ export const writeGoogleSheetAction: AiFlowActionActivity< vaultClient: VaultClient; } > = async ({ inputs, vaultClient }) => { - const { flowEntityId, stepId, userAuthentication, webId } = - await getFlowContext(); + const { flowEntityId, stepId, userAuthentication, webId } = await getFlowContext(); - const { audience, dataToWrite, googleAccountId, googleSheet } = - getSimplifiedAiFlowActionInputs({ - inputs, - actionType: "writeGoogleSheet", - }); + const { audience, dataToWrite, googleAccountId, googleSheet } = getSimplifiedAiFlowActionInputs({ + inputs, + actionType: "writeGoogleSheet", + }); /** * 1. Confirm that the Google account exists and has valid credentials associated with it @@ -184,12 +179,11 @@ export const writeGoogleSheetAction: AiFlowActionActivity< const queryFilter = "persistedEntities" in resolvedDataToWrite ? { - any: resolvedDataToWrite.persistedEntities.map( - (persistedEntityMetadata) => - generateEntityIdFilter({ - entityId: persistedEntityMetadata.entityId, - includeArchived: false, - }), + any: resolvedDataToWrite.persistedEntities.map((persistedEntityMetadata) => + generateEntityIdFilter({ + entityId: persistedEntityMetadata.entityId, + includeArchived: false, + }), ), } : await getFilterFromBlockProtocolQueryEntity({ @@ -257,12 +251,9 @@ export const writeGoogleSheetAction: AiFlowActionActivity< * the spreadsheetId as a heartbeat. This avoids us creating a duplicate spreadsheet when the activity is retried. */ const { spreadsheetId: spreadsheetIdFromFailedAttempt } = - (Context.current().info.heartbeatDetails as - | ActivityHeartbeatDetails - | undefined) ?? {}; + (Context.current().info.heartbeatDetails as ActivityHeartbeatDetails | undefined) ?? {}; - const newSheetName = - "newSheetName" in googleSheet ? googleSheet.newSheetName : undefined; + const newSheetName = "newSheetName" in googleSheet ? googleSheet.newSheetName : undefined; const existingSpreadsheetId = spreadsheetIdFromFailedAttempt ?? @@ -341,9 +332,7 @@ export const writeGoogleSheetAction: AiFlowActionActivity< }, }, ...existingSheets - .filter( - (sheet) => sheet.properties?.sheetId !== placeholderFirstSheetId, - ) + .filter((sheet) => sheet.properties?.sheetId !== placeholderFirstSheetId) .map((sheet) => ({ deleteSheet: { sheetId: sheet.properties?.sheetId, @@ -364,44 +353,36 @@ export const writeGoogleSheetAction: AiFlowActionActivity< */ const fileProperties: GoogleSheetsFile["propertiesWithMetadata"] = { value: { - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": - { - value: spreadsheet.properties?.title ?? "Untitled", - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": { + value: spreadsheet.properties?.title ?? "Untitled", + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": - { - value: spreadsheet.spreadsheetUrl, - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": { + value: spreadsheet.spreadsheetUrl, + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": - { - value: spreadsheet.properties?.title ?? "Untitled", - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": { + value: spreadsheet.properties?.title ?? "Untitled", + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, + }, "https://hash.ai/@h/types/property-type/file-id/": { value: spreadsheet.spreadsheetId, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": - { - value: "application/vnd.google-apps.spreadsheet", - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": { + value: "application/vnd.google-apps.spreadsheet", + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, + }, "https://hash.ai/@h/types/property-type/data-audience/": { value: audience, metadata: { @@ -442,10 +423,7 @@ export const writeGoogleSheetAction: AiFlowActionActivity< { equal: [ { - path: [ - "properties", - systemPropertyTypes.fileId.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.fileId.propertyTypeBaseUrl], }, { parameter: spreadsheet.spreadsheetId }, ], @@ -457,11 +435,10 @@ export const writeGoogleSheetAction: AiFlowActionActivity< let entityToReturn: HashEntity; if (existingEntity) { - const { existingEntityIsDraft, isExactMatch, patchOperations } = - getEntityUpdate({ - existingEntity, - newPropertiesWithMetadata: fileProperties, - }); + const { existingEntityIsDraft, isExactMatch, patchOperations } = getEntityUpdate({ + existingEntity, + newPropertiesWithMetadata: fileProperties, + }); if (isExactMatch) { entityToReturn = existingEntity; @@ -494,9 +471,7 @@ export const writeGoogleSheetAction: AiFlowActionActivity< { actorId: webBotActorId }, { draft: false, - entityTypeIds: [ - systemLinkEntityTypes.associatedWithAccount.linkEntityTypeId, - ], + entityTypeIds: [systemLinkEntityTypes.associatedWithAccount.linkEntityTypeId], webId, linkData: { leftEntityId: entityToReturn.metadata.recordId.entityId, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-csv-to-sheet-requests.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-csv-to-sheet-requests.ts index 456a62b4cd0..41b340d6575 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-csv-to-sheet-requests.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-csv-to-sheet-requests.ts @@ -32,9 +32,7 @@ export const convertCsvToSheetRequests = ({ skipEmptyLines: "greedy", // ignore empty lines, whitespace counts as empty }); } catch (err) { - throw new Error( - `Could not parse csvString content: ${(err as Error).message}`, - ); + throw new Error(`Could not parse csvString content: ${(err as Error).message}`); } const data = parsedCsv.data; diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-subgraph-to-sheet-requests.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-subgraph-to-sheet-requests.ts index 2645510d12c..1ded2523b89 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-subgraph-to-sheet-requests.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/convert-subgraph-to-sheet-requests.ts @@ -10,19 +10,12 @@ import { getEntityTypeById, getPropertyTypeForEntity, } from "@blockprotocol/graph/stdlib"; -import { - typedEntries, - typedKeys, - typedValues, -} from "@local/advanced-types/typed-entries"; +import { typedEntries, typedKeys, typedValues } from "@local/advanced-types/typed-entries"; import { isDraftEntity } from "@local/hash-isomorphic-utils/entity-store"; import { generateEntityLabel } from "@local/hash-isomorphic-utils/generate-entity-label"; import { blockProtocolEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; -import { - createCellFromValue, - createHyperlinkCell, -} from "./shared/create-sheet-data.js"; +import { createCellFromValue, createHyperlinkCell } from "./shared/create-sheet-data.js"; import { cellHeaderFormat } from "./shared/format.js"; import type { SheetOutputFormat } from "./shared/config.js"; @@ -96,10 +89,7 @@ const createColumnsForEntity = ( let nextColumnIndex = baseColumnCount; - const entityTypeAndParents = getEntityTypeAndParentsById( - subgraph, - entityType.$id, - ); + const entityTypeAndParents = getEntityTypeAndParentsById(subgraph, entityType.$id); const properties = new Set(); const links = new Set(); @@ -114,8 +104,7 @@ const createColumnsForEntity = ( } const isLinkType = entityTypeAndParents.some( - (ancestor) => - ancestor.schema.$id === blockProtocolEntityTypes.link.entityTypeId, + (ancestor) => ancestor.schema.$id === blockProtocolEntityTypes.link.entityTypeId, ); if (isLinkType) { @@ -134,11 +123,7 @@ const createColumnsForEntity = ( const baseAndLinkDataColumnCount = nextColumnIndex; for (const baseUrl of [...properties]) { - const { propertyType } = getPropertyTypeForEntity( - subgraph, - [entityType.$id], - baseUrl, - ); + const { propertyType } = getPropertyTypeForEntity(subgraph, [entityType.$id], baseUrl); columns[`properties.${baseUrl}`] = { baseOrVersionedUrl: baseUrl, columnLetter: columnIndexToColumnLetters(nextColumnIndex), @@ -158,15 +143,12 @@ const createColumnsForEntity = ( columns[`links.${linkTypeId}`] = { baseOrVersionedUrl: linkTypeId, columnLetter: columnIndexToColumnLetters(nextColumnIndex), - label: humanReadable - ? linkEntityType.schema.title - : `links.${linkTypeId}`, + label: humanReadable ? linkEntityType.schema.title : `links.${linkTypeId}`, }; nextColumnIndex++; } - const linkColumnCount = - nextColumnIndex - propertyColumnCount - baseAndLinkDataColumnCount; + const linkColumnCount = nextColumnIndex - propertyColumnCount - baseAndLinkDataColumnCount; return { baseColumnCount, @@ -225,9 +207,7 @@ export const convertSubgraphToSheetRequests = ({ /** Within link entities, sort them by the source (left) entityId, so we can link to a range of rows from the source */ if (aEntity.linkData && bEntity.linkData) { - return aEntity.linkData.leftEntityId.localeCompare( - bEntity.linkData.leftEntityId, - ); + return aEntity.linkData.leftEntityId.localeCompare(bEntity.linkData.leftEntityId); } /** @@ -235,15 +215,9 @@ export const convertSubgraphToSheetRequests = ({ * of multiple editions) */ return ( - aEntity.metadata.recordId.entityId.localeCompare( - bEntity.metadata.recordId.entityId, - ) || - new Date( - aEntity.metadata.temporalVersioning.decisionTime.start.limit, - ).valueOf() - - new Date( - bEntity.metadata.temporalVersioning.decisionTime.start.limit, - ).valueOf() + aEntity.metadata.recordId.entityId.localeCompare(bEntity.metadata.recordId.entityId) || + new Date(aEntity.metadata.temporalVersioning.decisionTime.start.limit).valueOf() - + new Date(bEntity.metadata.temporalVersioning.decisionTime.start.limit).valueOf() ); }); @@ -295,13 +269,8 @@ export const convertSubgraphToSheetRequests = ({ const typeId = entityType.schema.$id; const typeVersion = entityType.metadata.recordId.version; - const { - columns, - baseColumnCount, - isLinkType, - linkColumnCount, - propertyColumnCount, - } = createColumnsForEntity(entityType.schema, subgraph, format); + const { columns, baseColumnCount, isLinkType, linkColumnCount, propertyColumnCount } = + createColumnsForEntity(entityType.schema, subgraph, format); /** * If we haven't yet created a sheet for this entity type, add it to the map and add its header row(s) @@ -326,11 +295,9 @@ export const convertSubgraphToSheetRequests = ({ (isLinkType ? index === baseColumnCount + 1 || index === baseColumnCount + propertyColumnCount + 1 || - index === - baseColumnCount + propertyColumnCount + linkColumnCount + 1 + index === baseColumnCount + propertyColumnCount + linkColumnCount + 1 : index === baseColumnCount + propertyColumnCount - 1 || - index === - baseColumnCount + propertyColumnCount + linkColumnCount - 1); + index === baseColumnCount + propertyColumnCount + linkColumnCount - 1); return { userEnteredValue: { @@ -481,9 +448,7 @@ export const convertSubgraphToSheetRequests = ({ const thisRowIndex = entitySheetRequests[typeId].rows.length; - const lastColumnLetter = columnIndexToColumnLetters( - Object.keys(columns).length - 1, - ); + const lastColumnLetter = columnIndexToColumnLetters(Object.keys(columns).length - 1); /** * Store this entity's position in the sheet, so we can link to it from sheets for link types. @@ -504,9 +469,7 @@ export const convertSubgraphToSheetRequests = ({ for (const key of Object.keys(columns)) { if (key === "entityId") { - entityCells.push( - createCellFromValue({ value: entity.metadata.recordId.entityId }), - ); + entityCells.push(createCellFromValue({ value: entity.metadata.recordId.entityId })); } else if (key === "label") { entityCells.push( createCellFromValue({ @@ -559,9 +522,7 @@ export const convertSubgraphToSheetRequests = ({ label: generateEntityLabel(subgraph, linkedEntity), sheetId, startCellInclusive: `A${rowIndex + 1}`, - endCellInclusive: `${entityPosition.lastColumnLetter}${ - rowIndex + 1 - }`, + endCellInclusive: `${entityPosition.lastColumnLetter}${rowIndex + 1}`, }), ); @@ -581,8 +542,7 @@ export const convertSubgraphToSheetRequests = ({ * This is the first time we've seen this entity as a source in this sheet, set the sheetId and start * index */ - outgoingLinkMapForLeftEntity.sheetId = - entitySheetRequests[typeId].sheetId; + outgoingLinkMapForLeftEntity.sheetId = entitySheetRequests[typeId].sheetId; outgoingLinkMapForLeftEntity.startRowIndex = thisRowIndex; outgoingLinkMapForLeftEntity.lastColumnLetter = lastColumnLetter; } @@ -621,9 +581,7 @@ export const convertSubgraphToSheetRequests = ({ label: generateEntityLabel(subgraph, linkedEntity), sheetId, startCellInclusive: `A${rowIndex + 1}`, - endCellInclusive: `${entityPosition.lastColumnLetter}${ - rowIndex + 1 - }`, + endCellInclusive: `${entityPosition.lastColumnLetter}${rowIndex + 1}`, }), ); } else { @@ -656,10 +614,9 @@ export const convertSubgraphToSheetRequests = ({ const requests: sheets_v4.Schema$Request[] = []; - for (const [ - typeId, - { additionalRequests, sheetId, rows, typeTitle }, - ] of Object.entries(entitySheetRequests)) { + for (const [typeId, { additionalRequests, sheetId, rows, typeTitle }] of Object.entries( + entitySheetRequests, + )) { // @todo add discriminator to sheet titles to differentiate between types with identical titles, for human readers // const typesWithIdenticalTitles = Object.entries(entitySheetRequests).filter( // ([_typeId, entitySheetRequest]) => @@ -745,9 +702,7 @@ export const convertSubgraphToSheetRequests = ({ continue; } - for (const [_linkTypeId, outgoingLinkRange] of Object.entries( - outgoingLinkRanges, - )) { + for (const [_linkTypeId, outgoingLinkRange] of Object.entries(outgoingLinkRanges)) { if ( outgoingLinkRange.sheetId !== undefined && outgoingLinkRange.startRowIndex !== undefined && @@ -770,9 +725,7 @@ export const convertSubgraphToSheetRequests = ({ createHyperlinkCell({ label: `View links`, sheetId: outgoingLinkRange.sheetId, - startCellInclusive: `A${ - outgoingLinkRange.startRowIndex + 1 - }`, + startCellInclusive: `A${outgoingLinkRange.startRowIndex + 1}`, endCellInclusive: `${outgoingLinkRange.lastColumnLetter}${ outgoingLinkRange.endRowIndex + 1 }`, diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-filter-from-bp-query-entity.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-filter-from-bp-query-entity.ts index d148e3e559e..b4921a503cf 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-filter-from-bp-query-entity.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-filter-from-bp-query-entity.ts @@ -30,9 +30,7 @@ export const getFilterFromBlockProtocolQueryEntity = async ({ } const multiFilter = - queryEntity.properties[ - "https://blockprotocol.org/@hash/types/property-type/query/" - ]; + queryEntity.properties["https://blockprotocol.org/@hash/types/property-type/query/"]; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- additional check in case another entity is used that has this optional if (!multiFilter) { diff --git a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-subgraph-from-filter.ts b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-subgraph-from-filter.ts index bf2735ef109..30578d7589f 100644 --- a/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-subgraph-from-filter.ts +++ b/apps/hash-ai-worker-ts/src/activities/flow-activities/write-google-sheet-action/get-subgraph-from-filter.ts @@ -2,11 +2,7 @@ import { queryEntitySubgraph } from "@local/hash-graph-sdk/entity"; import { currentTimeInstantTemporalAxes } from "@local/hash-isomorphic-utils/graph-queries"; import type { ActorEntityUuid } from "@blockprotocol/type-system"; -import type { - EntityTraversalPath, - Filter, - GraphApi, -} from "@local/hash-graph-client"; +import type { EntityTraversalPath, Filter, GraphApi } from "@local/hash-graph-client"; export const getSubgraphFromFilter = async ({ authentication, diff --git a/apps/hash-ai-worker-ts/src/activities/get-ai-assistant-account-id-activity.ts b/apps/hash-ai-worker-ts/src/activities/get-ai-assistant-account-id-activity.ts index 4506e34f484..7f84efafe54 100644 --- a/apps/hash-ai-worker-ts/src/activities/get-ai-assistant-account-id-activity.ts +++ b/apps/hash-ai-worker-ts/src/activities/get-ai-assistant-account-id-activity.ts @@ -12,8 +12,7 @@ export const getAiAssistantAccountIdActivity = async (params: { grantCreatePermissionForWeb?: WebId; graphApiClient: GraphApi; }): Promise => { - const { authentication, graphApiClient, grantCreatePermissionForWeb } = - params; + const { authentication, graphApiClient, grantCreatePermissionForWeb } = params; const aiAssistantAccountId = await getAiIdByIdentifier( { graphApi: graphApiClient }, @@ -36,14 +35,10 @@ export const getAiAssistantAccountIdActivity = async (params: { // If the AI assistant is not a member of the web, we need to add them as a member. // This can only be done if the user is an administrator of the web. if (!webRole) { - const isWebAdmin = await getActorGroupRole( - graphApiClient, - authentication, - { - actorId: authentication.actorId, - actorGroupId: grantCreatePermissionForWeb, - }, - ).then((role) => role === "administrator"); + const isWebAdmin = await getActorGroupRole(graphApiClient, authentication, { + actorId: authentication.actorId, + actorGroupId: grantCreatePermissionForWeb, + }).then((role) => role === "administrator"); if (isWebAdmin) { await addActorGroupMember(graphApiClient, authentication, { diff --git a/apps/hash-ai-worker-ts/src/activities/get-dereferenced-entity-types-activity.ts b/apps/hash-ai-worker-ts/src/activities/get-dereferenced-entity-types-activity.ts index 1c28e99a5a8..7b1958ab8d9 100644 --- a/apps/hash-ai-worker-ts/src/activities/get-dereferenced-entity-types-activity.ts +++ b/apps/hash-ai-worker-ts/src/activities/get-dereferenced-entity-types-activity.ts @@ -87,9 +87,7 @@ export const getDereferencedEntityTypesActivity = async (params: { // ...and that link must not have destination constraints which cannot be met !( "oneOf" in targetSchema.items && - !targetSchema.items.oneOf.some( - (targetOption) => entityTypes[targetOption.$ref], - ) + !targetSchema.items.oneOf.some((targetOption) => entityTypes[targetOption.$ref]) ), ), ); diff --git a/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ai.test.ts index c9df13254b8..884ca1b375a 100644 --- a/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ai.test.ts @@ -1,10 +1,7 @@ import "../shared/testing-utilities/mock-get-flow-context.js"; import { expect, test } from "vitest"; -import { - getWebPageActivity, - sanitizeHtmlForLlmConsumption, -} from "./get-web-page-activity.js"; +import { getWebPageActivity, sanitizeHtmlForLlmConsumption } from "./get-web-page-activity.js"; import type { Url } from "@blockprotocol/type-system"; diff --git a/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ts b/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ts index e04d8e85dab..8e9a015780f 100644 --- a/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ts +++ b/apps/hash-ai-worker-ts/src/activities/get-web-page-activity.ts @@ -12,10 +12,7 @@ import { getFlowContext } from "./shared/get-flow-context.js"; import { requestExternalInput } from "./shared/request-external-input.js"; import type { Url } from "@blockprotocol/type-system"; -import type { - FlowInternetAccessSettings, - WebPage, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { FlowInternetAccessSettings, WebPage } from "@local/hash-isomorphic-utils/flows/types"; const sliceContentForLlmConsumption = (params: { content: string; @@ -63,14 +60,7 @@ const disallowedTags = ["script", "style", "link", "canvas", "svg"]; * The tags that will be filtered from the HTML content if they don't have * any of the relevant attributes (defined in `allowedAttributes`). */ -const disallowedTagsWithNoRelevantAttributes = [ - "div", - "span", - "strong", - "b", - "i", - "em", -]; +const disallowedTagsWithNoRelevantAttributes = ["div", "span", "strong", "b", "i", "em"]; export const sanitizeHtmlForLlmConsumption = (params: { htmlContent: string; @@ -79,9 +69,7 @@ export const sanitizeHtmlForLlmConsumption = (params: { const { htmlContent, maximumNumberOfTokens } = params; const sanitizedHtml = sanitizeHtml(htmlContent, { - allowedTags: sanitizeHtml.defaults.allowedTags.filter( - (tag) => !disallowedTags.includes(tag), - ), + allowedTags: sanitizeHtml.defaults.allowedTags.filter((tag) => !disallowedTags.includes(tag)), allowedAttributes: { "*": allowedAttributes }, disallowedTagsMode: "discard", }); @@ -89,9 +77,7 @@ export const sanitizeHtmlForLlmConsumption = (params: { const dom = new JSDOM(sanitizedHtml); const document = dom.window.document; - const elements = document.querySelectorAll( - disallowedTagsWithNoRelevantAttributes.join(","), - ); + const elements = document.querySelectorAll(disallowedTagsWithNoRelevantAttributes.join(",")); for (const element of elements) { if (!element.attributes.length) { @@ -110,14 +96,8 @@ export const sanitizeHtmlForLlmConsumption = (params: { /** * Cut repeated newlines and tabs to a maximum of 2. */ - sanitizedHtmlWithNoDisallowedTags = sanitizedHtmlWithNoDisallowedTags.replace( - /\n{3,}/g, - "\n\n", - ); - sanitizedHtmlWithNoDisallowedTags = sanitizedHtmlWithNoDisallowedTags.replace( - /\t{3,}$/g, - "\t\t", - ); + sanitizedHtmlWithNoDisallowedTags = sanitizedHtmlWithNoDisallowedTags.replace(/\n{3,}/g, "\n\n"); + sanitizedHtmlWithNoDisallowedTags = sanitizedHtmlWithNoDisallowedTags.replace(/\t{3,}$/g, "\t\t"); const slicedSanitizedHtml = sliceContentForLlmConsumption({ content: sanitizedHtmlWithNoDisallowedTags, @@ -138,10 +118,7 @@ const getRemoteBrowserWsEndpoint = (): string => { return endpoint; }; -const maxConcurrentSessions = parseInt( - process.env.BROWSER_MAX_CONCURRENT_SESSIONS ?? "2", - 10, -); +const maxConcurrentSessions = parseInt(process.env.BROWSER_MAX_CONCURRENT_SESSIONS ?? "2", 10); let activeSessions = 0; const sessionQueue: Array<() => void> = []; @@ -167,9 +144,7 @@ const releaseSessionSlot = () => { } }; -const getWebPageFromRemoteBrowser = async ( - url: Url, -): Promise => { +const getWebPageFromRemoteBrowser = async (url: Url): Promise => { await acquireSessionSlot(); let browser: puppeteer.Browser | undefined; @@ -197,9 +172,7 @@ const getWebPageFromRemoteBrowser = async ( } if (response.status() < 200 || response.status() >= 300) { - throw new Error( - `Page load failed: ${response.status()}: ${response.statusText()}`, - ); + throw new Error(`Page load failed: ${response.status()}: ${response.statusText()}`); } await page.waitForSelector("body", { timeout: 5_000 }); @@ -230,9 +203,7 @@ const getWebPageFromRemoteBrowser = async ( } }; -const getWebPageFromBrowser = async ( - url: Url, -): Promise => { +const getWebPageFromBrowser = async (url: Url): Promise => { const externalResponse = await requestExternalInput({ requestId: generateUuid(), stepId: Context.current().info.activityId, @@ -287,9 +258,7 @@ export const getWebPageActivity = async (params: { const shouldAskBrowser = browserPluginSettings.enabled && (browserPluginSettings.domains.includes(urlObject.host) || - browserPluginSettings.domains.some((domain) => - urlObject.host.endsWith(`.${domain}`), - )) && + browserPluginSettings.domains.some((domain) => urlObject.host.endsWith(`.${domain}`))) && /** * @todo: find way to mock the temporal context to allow for accessing the * browser plugin in tests. diff --git a/apps/hash-ai-worker-ts/src/activities/get-web-search-results-activity.ts b/apps/hash-ai-worker-ts/src/activities/get-web-search-results-activity.ts index bcb37090af3..1ed85348dd3 100644 --- a/apps/hash-ai-worker-ts/src/activities/get-web-search-results-activity.ts +++ b/apps/hash-ai-worker-ts/src/activities/get-web-search-results-activity.ts @@ -1,8 +1,6 @@ import { internalApiClient } from "@local/hash-backend-utils/internal-api-client"; -export const getWebSearchResultsActivity = async (params: { - query: string; -}) => { +export const getWebSearchResultsActivity = async (params: { query: string }) => { const { data: { webSearchResults }, } = await internalApiClient.getWebSearchResults(params.query); diff --git a/apps/hash-ai-worker-ts/src/activities/graph.ts b/apps/hash-ai-worker-ts/src/activities/graph.ts index 9d7229b4d9b..738a646002a 100644 --- a/apps/hash-ai-worker-ts/src/activities/graph.ts +++ b/apps/hash-ai-worker-ts/src/activities/graph.ts @@ -79,15 +79,8 @@ export type EntityQueryResponse = { cursor?: EntityQueryCursor | null; }; -export const createGraphActivities = ({ - graphApiClient, -}: { - graphApiClient: GraphApi; -}) => ({ - async getSystemMachineIds(params: { - cursor?: EntityQueryCursor; - limit?: number; - }): Promise<{ +export const createGraphActivities = ({ graphApiClient }: { graphApiClient: GraphApi }) => ({ + async getSystemMachineIds(params: { cursor?: EntityQueryCursor; limit?: number }): Promise<{ machineIds: EntityId[]; cursor?: EntityQueryCursor | null; }> { @@ -115,10 +108,7 @@ export const createGraphActivities = ({ { startsWith: [ { - path: [ - "properties", - systemPropertyTypes.machineIdentifier.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.machineIdentifier.propertyTypeBaseUrl], }, { parameter: "system-" }, ], @@ -143,66 +133,48 @@ export const createGraphActivities = ({ authentication: AuthenticationContext; request: QueryDataTypesParams; }): Promise { - return queryDataTypes( - graphApiClient, - params.authentication, - params.request, - ); + return queryDataTypes(graphApiClient, params.authentication, params.request); }, async queryDataTypeSubgraph(params: { authentication: AuthenticationContext; request: QueryDataTypeSubgraphParams; }): Promise { - return queryDataTypeSubgraph( - graphApiClient, - params.authentication, - params.request, - ).then(serializeQueryDataTypeSubgraphResponse); + return queryDataTypeSubgraph(graphApiClient, params.authentication, params.request).then( + serializeQueryDataTypeSubgraphResponse, + ); }, async queryPropertyTypes(params: { authentication: AuthenticationContext; request: QueryPropertyTypesParams; }): Promise { - return queryPropertyTypes( - graphApiClient, - params.authentication, - params.request, - ); + return queryPropertyTypes(graphApiClient, params.authentication, params.request); }, async queryPropertyTypeSubgraph(params: { authentication: AuthenticationContext; request: QueryPropertyTypeSubgraphParams; }): Promise { - return queryPropertyTypeSubgraph( - graphApiClient, - params.authentication, - params.request, - ).then(serializeQueryPropertyTypeSubgraphResponse); + return queryPropertyTypeSubgraph(graphApiClient, params.authentication, params.request).then( + serializeQueryPropertyTypeSubgraphResponse, + ); }, async queryEntityTypes(params: { authentication: AuthenticationContext; request: QueryEntityTypesParams; }): Promise { - return queryEntityTypes( - graphApiClient, - params.authentication, - params.request, - ); + return queryEntityTypes(graphApiClient, params.authentication, params.request); }, async queryEntityTypeSubgraph(params: { authentication: AuthenticationContext; request: QueryEntityTypeSubgraphParams; }): Promise { - return queryEntityTypeSubgraph( - graphApiClient, - params.authentication, - params.request, - ).then(serializeQueryEntityTypeSubgraphResponse); + return queryEntityTypeSubgraph(graphApiClient, params.authentication, params.request).then( + serializeQueryEntityTypeSubgraphResponse, + ); }, async queryEntities(params: { @@ -211,11 +183,9 @@ export const createGraphActivities = ({ }; request: QueryEntitiesRequest; }): Promise { - return queryEntities( - { graphApi: graphApiClient }, - params.authentication, - params.request, - ).then(serializeQueryEntitiesResponse); + return queryEntities({ graphApi: graphApiClient }, params.authentication, params.request).then( + serializeQueryEntitiesResponse, + ); }, async queryEntitySubgraph(params: { @@ -304,27 +274,17 @@ export const createGraphActivities = ({ }, // eslint-disable-next-line @typescript-eslint/require-await - async getSubgraphEntities(params: { - subgraph: SerializedSubgraph; - }): Promise { - return getEntities(deserializeSubgraph(params.subgraph), false).map( - (entity) => entity.toJSON(), + async getSubgraphEntities(params: { subgraph: SerializedSubgraph }): Promise { + return getEntities(deserializeSubgraph(params.subgraph), false).map((entity) => + entity.toJSON(), ); }, - async createEntity( - authentication: AuthenticationContext, - params: CreateEntityParameters, - ) { + async createEntity(authentication: AuthenticationContext, params: CreateEntityParameters) { return HashEntity.create(graphApiClient, authentication, params); }, - async getHashInstanceAdminAccountGroupId(authentication: { - actorId: ActorEntityUuid; - }) { - return getInstanceAdminsTeam( - { graphApi: graphApiClient }, - authentication, - ).then(({ id }) => id); + async getHashInstanceAdminAccountGroupId(authentication: { actorId: ActorEntityUuid }) { + return getInstanceAdminsTeam({ graphApi: graphApiClient }, authentication).then(({ id }) => id); }, }); diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities-from-web-page-activity.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities-from-web-page-activity.ts index caadf26330e..1ce6e9b8810 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities-from-web-page-activity.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities-from-web-page-activity.ts @@ -63,9 +63,7 @@ export const inferEntitiesFromWebPageActivity = async (params: { webId, }); - logger.debug( - `Inference state after entity summaries: ${stringify(inferenceState)}`, - ); + logger.debug(`Inference state after entity summaries: ${stringify(inferenceState)}`); if (status.code !== StatusCode.Ok) { logger.error( @@ -99,9 +97,7 @@ export const inferEntitiesFromWebPageActivity = async (params: { change units, you must use the units specified in the data. You already provided a summary of the ${ - relevantEntitiesPrompt - ? "relevant entities you inferred" - : "entities you can infer" + relevantEntitiesPrompt ? "relevant entities you inferred" : "entities you can infer" } from the website. Here it is: ${JSON.stringify(Object.values(inferenceState.proposedEntitySummaries))} `); diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries-from-web-page.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries-from-web-page.ts index c346eb491f7..e2483cca525 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries-from-web-page.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries-from-web-page.ts @@ -3,10 +3,7 @@ import dedent from "dedent"; import { inferEntitySummaries } from "./infer-entity-summaries.js"; import type { PermittedOpenAiModel } from "../shared/openai-client.js"; -import type { - DereferencedEntityTypesByTypeId, - InferenceState, -} from "./inference-types.js"; +import type { DereferencedEntityTypesByTypeId, InferenceState } from "./inference-types.js"; import type { EntityId, UserId, WebId } from "@blockprotocol/type-system"; import type { GraphApi } from "@local/hash-graph-client"; import type { WebPage } from "@local/hash-isomorphic-utils/flows/types"; @@ -59,9 +56,7 @@ export const inferEntitySummariesFromWebPage = async (params: { } For entities that link other entities together, the sourceEntityId must correspond to an entityId of an entity you provide, as must the targetEntityId. I'm about to provide you with the content of a website${ - typeof webPage === "string" - ? "" - : ` hosted at ${webPage.url}, titled ${webPage.title}` + typeof webPage === "string" ? "" : ` hosted at ${webPage.url}, titled ${webPage.title}` }. ${ relevantEntitiesPrompt diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries.ts index 26c0e5875ba..6d9f98662f4 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries.ts @@ -28,12 +28,7 @@ import type { InferenceState, ProposedEntitySummary, } from "./inference-types.js"; -import type { - EntityId, - UserId, - VersionedUrl, - WebId, -} from "@blockprotocol/type-system"; +import type { EntityId, UserId, VersionedUrl, WebId } from "@blockprotocol/type-system"; import type { GraphApi } from "@local/hash-graph-client"; import type { Status } from "@local/status"; import type OpenAI from "openai"; @@ -131,9 +126,7 @@ export const inferEntitySummaries = async (params: { )[], proposedEntitySummaries: ProposedEntitySummary[], ) => { - logger.debug( - `Retrying with additional message: ${stringify(retryMessages)}`, - ); + logger.debug(`Retrying with additional message: ${stringify(retryMessages)}`); const newMessages = [ ...completionPayload.messages, @@ -174,9 +167,7 @@ export const inferEntitySummaries = async (params: { } case "length": { - logger.error( - `AI Model returned 'length' finish reason on attempt ${iterationCount}.`, - ); + logger.error(`AI Model returned 'length' finish reason on attempt ${iterationCount}.`); const toolCallId = toolCalls[0]?.id; @@ -243,8 +234,7 @@ export const inferEntitySummaries = async (params: { if (toolCall.name === "register_entity_summaries") { let proposedEntitySummariesByType: ProposedEntitySummariesByType; try { - proposedEntitySummariesByType = - toolCall.input as ProposedEntitySummariesByType; + proposedEntitySummariesByType = toolCall.input as ProposedEntitySummariesByType; } catch (err) { logger.error( `Model provided invalid argument to register_entity_summaries function. Argument provided: ${stringify( @@ -253,21 +243,18 @@ export const inferEntitySummaries = async (params: { ); retryMessages.push({ - content: `Invalid JSON, please try again: ${ - (err as Error).message - }`, + content: `Invalid JSON, please try again: ${(err as Error).message}`, role: "tool", tool_call_id: toolCall.id, }); continue; } - const { validSummaries, errorMessage } = - validateEntitySummariesByType({ - parsedJson: proposedEntitySummariesByType, - entityTypesById: entityTypes, - existingSummaries: inferenceState.proposedEntitySummaries, - }); + const { validSummaries, errorMessage } = validateEntitySummariesByType({ + parsedJson: proposedEntitySummariesByType, + entityTypesById: entityTypes, + existingSummaries: inferenceState.proposedEntitySummaries, + }); for (const validSummary of validSummaries) { if ( @@ -292,9 +279,7 @@ export const inferEntitySummaries = async (params: { } } - const typesWithNoSuggestionsToRerequest = Object.values( - entityTypes, - ).filter( + const typesWithNoSuggestionsToRerequest = Object.values(entityTypes).filter( ({ schema }) => // We track which types we've already requested the model try again for – we won't ask again !providedOrRerequestedEntityTypes.has(schema.$id), @@ -308,22 +293,16 @@ export const inferEntitySummaries = async (params: { logger.info( // @todo: https://linear.app/hash/issue/H-3769/investigate-new-eslint-errors // eslint-disable-next-line @typescript-eslint/no-base-to-string - `No suggestions for entity types: ${typesWithNoSuggestionsToRerequest.join( - ", ", - )}`, + `No suggestions for entity types: ${typesWithNoSuggestionsToRerequest.join(", ")}`, ); for (const { schema } of typesWithNoSuggestionsToRerequest) { providedOrRerequestedEntityTypes.add(schema.$id); } - const isMissingEntities = typesWithNoSuggestionsToRerequest.some( - ({ isLink }) => !isLink, - ); + const isMissingEntities = typesWithNoSuggestionsToRerequest.some(({ isLink }) => !isLink); - const isMissingLinks = typesWithNoSuggestionsToRerequest.some( - ({ isLink }) => isLink, - ); + const isMissingLinks = typesWithNoSuggestionsToRerequest.some(({ isLink }) => isLink); const missingContentKinds = `${isMissingEntities ? "entities" : ""}${ isMissingEntities && isMissingLinks ? " or " : "" @@ -350,9 +329,7 @@ export const inferEntitySummaries = async (params: { const toolCallsWithoutProblems = toolCalls.filter( (toolCall) => - !retryMessages.some( - (msg) => msg.role === "tool" && msg.tool_call_id === toolCall.id, - ), + !retryMessages.some((msg) => msg.role === "tool" && msg.tool_call_id === toolCall.id), ); /** @@ -367,10 +344,7 @@ export const inferEntitySummaries = async (params: { })), ); - return retryWithMessages( - retryMessages, - inferenceState.proposedEntitySummaries, - ); + return retryWithMessages(retryMessages, inferenceState.proposedEntitySummaries); } } diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries/generate-summary-tools.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries/generate-summary-tools.ts index 8a6148ba89b..14762e181a6 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries/generate-summary-tools.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/infer-entity-summaries/generate-summary-tools.ts @@ -6,10 +6,7 @@ import { generateToolLinkFields } from "../shared/generate-propose-entities-tool import type { DereferencedEntityType } from "../../shared/dereference-entity-type.js"; import type { LlmToolDefinition } from "../../shared/get-llm-response/types.js"; -import type { - DereferencedEntityTypesByTypeId, - ProposedEntitySummary, -} from "../inference-types.js"; +import type { DereferencedEntityTypesByTypeId, ProposedEntitySummary } from "../inference-types.js"; import type { JsonObject } from "@blockprotocol/core"; import type { VersionedUrl } from "@blockprotocol/type-system"; import type { Subtype } from "@local/advanced-types/subtype"; @@ -37,20 +34,14 @@ export const validateEntitySummariesByType = (params: { const { parsedJson, entityTypesById, existingSummaries } = params; const errorMessages: string[] = []; - const validSummariesWithLinksUnchecked: ProposedEntitySummary[] = [ - ...existingSummaries, - ]; + const validSummariesWithLinksUnchecked: ProposedEntitySummary[] = [...existingSummaries]; - for (const [entityTypeId, summaryEntitiesForType] of typedEntries( - parsedJson, - )) { + for (const [entityTypeId, summaryEntitiesForType] of typedEntries(parsedJson)) { const typeIdValidationResult = validateVersionedUrl(entityTypeId); if (typeIdValidationResult.type !== "Ok") { errorMessages.push( - `The value '${stringify( - entityTypeId, - )}' for entityTypeId is not a valid versionedUrl`, + `The value '${stringify(entityTypeId)}' for entityTypeId is not a valid versionedUrl`, ); continue; } @@ -86,9 +77,7 @@ export const validateEntitySummariesByType = (params: { if (typeof entitySummary.entityId !== "number") { errorMessages.push( - `entityId must be a number, but is ${stringify( - entitySummary.entityId, - )}`, + `entityId must be a number, but is ${stringify(entitySummary.entityId)}`, ); currentEntityIsValid = false; } @@ -145,17 +134,13 @@ export const validateEntitySummariesByType = (params: { } return { - errorMessage: - errorMessages.length > 0 ? errorMessages.join("\n") : undefined, + errorMessage: errorMessages.length > 0 ? errorMessages.join("\n") : undefined, validSummaries, }; }; type CouldNotInferEntitiesReturnKey = "reason"; -type CouldNotInferEntitiesSchemaOrObject = Record< - CouldNotInferEntitiesReturnKey, - unknown ->; +type CouldNotInferEntitiesSchemaOrObject = Record; export type CouldNotInferEntitiesReturn = Subtype< CouldNotInferEntitiesSchemaOrObject, diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/inference-types.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/inference-types.ts index 0627109a847..a3967f9fe64 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/inference-types.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/inference-types.ts @@ -45,15 +45,9 @@ export type InferenceState = { /** A list of entities that can be inferred from the input, in summary form (no properties) */ proposedEntitySummaries: ProposedEntitySummary[]; /** A map of entity type IDs to a set of proposed entities, in entity form (with properties) */ - proposedEntityCreationsByType: Record< - VersionedUrl, - DeprecatedProposedEntity[] - >; + proposedEntityCreationsByType: Record; /** The results of attempting to persist entities inferred from the input */ - resultsByTemporaryId: Record< - number, - InferredEntityChangeResult | UpdateCandidate - >; + resultsByTemporaryId: Record; /** The token usage for each iteration, in order */ usage: LlmUsage[]; }; diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/persist-entities/generate-persist-entities-tools.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/persist-entities/generate-persist-entities-tools.ts index 0288ac0759b..bd4a461edf0 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/persist-entities/generate-persist-entities-tools.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/persist-entities/generate-persist-entities-tools.ts @@ -18,9 +18,7 @@ const stringifyArray = (array: unknown[]): string => * Validates that the provided object is a valid ProposedEntitiesByType object. * @throws Error if the provided object does not match ProposedEntitiesByType */ -export const validateProposedEntitiesByType = < - EntityUpdate extends boolean = false, ->( +export const validateProposedEntitiesByType = ( parsedJson: JsonObject, update: EntityUpdate, ): parsedJson is EntityUpdate extends true @@ -52,18 +50,12 @@ export const validateProposedEntitiesByType = < if (invalidArrays.length > 0) { throw new Error( - `Invalid entities arrays in AI-provided response: ${stringifyArray( - invalidArrays, - )}`, + `Invalid entities arrays in AI-provided response: ${stringifyArray(invalidArrays)}`, ); } const invalidEntities = maybeEntitiesArrays.flat().filter((maybeEntity) => { - if ( - maybeEntity === null || - typeof maybeEntity !== "object" || - Array.isArray(maybeEntity) - ) { + if (maybeEntity === null || typeof maybeEntity !== "object" || Array.isArray(maybeEntity)) { return true; } @@ -86,11 +78,7 @@ export const validateProposedEntitiesByType = < }); if (invalidEntities.length > 0) { - throw new Error( - `Invalid entities in AI-provided response: ${stringifyArray( - invalidEntities, - )}`, - ); + throw new Error(`Invalid entities in AI-provided response: ${stringifyArray(invalidEntities)}`); } return true; diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/propose-entities.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/propose-entities.ts index 94bfd16b081..01fb8d21300 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/propose-entities.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/propose-entities.ts @@ -19,14 +19,8 @@ import { extractErrorMessage } from "./shared/extract-validation-failure-details import { generateProposeEntitiesTools } from "./shared/generate-propose-entities-tools.js"; import { mapSimplifiedPropertiesToProperties } from "./shared/map-simplified-properties-to-properties.js"; -import type { - LlmMessage, - LlmUserMessage, -} from "../shared/get-llm-response/llm-message.js"; -import type { - DereferencedEntityTypesByTypeId, - InferenceState, -} from "./inference-types.js"; +import type { LlmMessage, LlmUserMessage } from "../shared/get-llm-response/llm-message.js"; +import type { DereferencedEntityTypesByTypeId, InferenceState } from "./inference-types.js"; import type { ProposedEntityToolCreationsByType } from "./shared/generate-propose-entities-tools.js"; import type { EntityUuid, VersionedUrl } from "@blockprotocol/type-system"; import type { DeprecatedProposedEntity } from "@local/hash-isomorphic-utils/ai-inference-types"; @@ -43,13 +37,7 @@ export const proposeEntities = async (params: { entityTypes: DereferencedEntityTypesByTypeId; inferenceState: InferenceState; }): Promise> => { - const { - maxTokens, - previousMessages, - entityTypes, - inferenceState, - firstUserMessage, - } = params; + const { maxTokens, previousMessages, entityTypes, inferenceState, firstUserMessage } = params; const { iterationCount, @@ -60,9 +48,7 @@ export const proposeEntities = async (params: { if (iterationCount > 30) { logger.info( - `Model reached maximum number of iterations. Messages: ${stringify( - previousMessages, - )}`, + `Model reached maximum number of iterations. Messages: ${stringify(previousMessages)}`, ); return { @@ -95,9 +81,7 @@ export const proposeEntities = async (params: { */ const spaceInQueue = 10 - inProgressEntityIds.length; for (let i = 0; i < spaceInQueue; i++) { - const nextProposedEntity = proposedEntitySummaries.find( - (entity) => !entity.takenFromQueue, - ); + const nextProposedEntity = proposedEntitySummaries.find((entity) => !entity.takenFromQueue); if (!nextProposedEntity) { break; } @@ -111,15 +95,13 @@ export const proposeEntities = async (params: { )}.`, ); - const { tools, simplifiedEntityTypeIdMappings } = - generateProposeEntitiesTools({ - entityTypes: Object.values(entityTypes), - }); + const { tools, simplifiedEntityTypeIdMappings } = generateProposeEntitiesTools({ + entityTypes: Object.values(entityTypes), + }); const entitiesToUpdate = inProgressEntityIds.filter( (inProgressEntityId) => - inferenceState.resultsByTemporaryId[inProgressEntityId]?.status === - "update-candidate", + inferenceState.resultsByTemporaryId[inProgressEntityId]?.status === "update-candidate", ); const entitiesToCreate = inProgressEntityIds.filter( @@ -134,9 +116,7 @@ export const proposeEntities = async (params: { entitiesToUpdate.length > 0 ? `update_entities with temporary ids ${entitiesToUpdate.join(", ")}` : null; - const innerMessage = [createMessage, updateMessage] - .filter(Boolean) - .join(" and "); + const innerMessage = [createMessage, updateMessage].filter(Boolean).join(" and "); const instructions = dedent(` Please make calls to ${innerMessage}. @@ -177,8 +157,7 @@ export const proposeEntities = async (params: { logger.debug("Next messages to model", { messages }); - const { userAuthentication, flowEntityId, stepId, webId } = - await getFlowContext(); + const { userAuthentication, flowEntityId, stepId, webId } = await getFlowContext(); const llmResponse = await getLlmResponse( { @@ -225,9 +204,7 @@ export const proposeEntities = async (params: { retryMessageContent: LlmUserMessage["content"]; requiresOriginalContext: boolean; }) => { - logger.debug( - `Retrying with additional message: ${stringify(retryMessageContent)}`, - ); + logger.debug(`Retrying with additional message: ${stringify(retryMessageContent)}`); const newMessages: LlmMessage[] = [ requiresOriginalContext @@ -285,9 +262,7 @@ export const proposeEntities = async (params: { } case "length": { - logger.error( - `AI Model returned 'length' finish reason on attempt ${iterationCount}.`, - ); + logger.error(`AI Model returned 'length' finish reason on attempt ${iterationCount}.`); const toolCallId = toolCalls[0]?.id; @@ -351,8 +326,7 @@ export const proposeEntities = async (params: { retryMessageContent.push({ type: "tool_result", - content: - "You provided an invalid argument to abandon_entities. Please try again", + content: "You provided an invalid argument to abandon_entities. Please try again", requiresOriginalContext: true, tool_use_id: toolCall.id, }); @@ -360,16 +334,13 @@ export const proposeEntities = async (params: { } // Remove the abandoned entities from the list of entities in progress - inferenceState.inProgressEntityIds = - inferenceState.inProgressEntityIds.filter( - (inProgressEntityId) => - !abandonedEntityIds.includes(inProgressEntityId), - ); + inferenceState.inProgressEntityIds = inferenceState.inProgressEntityIds.filter( + (inProgressEntityId) => !abandonedEntityIds.includes(inProgressEntityId), + ); } if (toolCall.name === "create_entities") { - const proposedEntitiesByType = - toolCall.input as ProposedEntityToolCreationsByType; + const proposedEntitiesByType = toolCall.input as ProposedEntityToolCreationsByType; try { validateProposedEntitiesByType(proposedEntitiesByType, false); @@ -382,8 +353,7 @@ export const proposeEntities = async (params: { retryMessageContent.push({ type: "tool_result", - content: - "You provided an invalid argument to create_entities. Please try again", + content: "You provided an invalid argument to create_entities. Please try again", requiresOriginalContext: true, tool_use_id: toolCall.id, }); @@ -403,8 +373,7 @@ export const proposeEntities = async (params: { const invalidProposedEntitiesOfType = await Promise.all( proposedEntitiesOfType.map(async (proposedEntityOfType) => { try { - const entityTypeId = - simplifiedEntityTypeIdMappings[simplifiedEntityTypeId]; + const entityTypeId = simplifiedEntityTypeIdMappings[simplifiedEntityTypeId]; if (!entityTypeId) { throw new Error( @@ -412,8 +381,7 @@ export const proposeEntities = async (params: { ); } - const { simplifiedPropertyTypeMappings } = - entityTypes[entityTypeId] ?? {}; + const { simplifiedPropertyTypeMappings } = entityTypes[entityTypeId] ?? {}; if (!simplifiedPropertyTypeMappings) { throw new Error( @@ -421,8 +389,7 @@ export const proposeEntities = async (params: { ); } - const { properties: simplifiedProperties } = - proposedEntityOfType; + const { properties: simplifiedProperties } = proposedEntityOfType; const properties = mergePropertyObjectAndMetadata( simplifiedProperties @@ -434,18 +401,15 @@ export const proposeEntities = async (params: { undefined, ); - await graphApiClient.validateEntity( - userAuthentication.actorId, - { - entityTypes: [entityTypeId], - components: { - linkData: false, - numItems: false, - requiredProperties: false, - }, - properties, + await graphApiClient.validateEntity(userAuthentication.actorId, { + entityTypes: [entityTypeId], + components: { + linkData: false, + numItems: false, + requiredProperties: false, }, - ); + properties, + }); return []; } catch (error) { @@ -481,44 +445,33 @@ export const proposeEntities = async (params: { } const validProposedEntitiesByType = Object.fromEntries( - typedEntries(proposedEntitiesByType).map< - [VersionedUrl, DeprecatedProposedEntity[]] - >(([simplifiedEntityTypeId, entities]) => { - const entityTypeId = - simplifiedEntityTypeIdMappings[simplifiedEntityTypeId]; - - if (!entityTypeId) { - throw new Error( - `Could not find entity type id for simplified entity type id ${simplifiedEntityTypeId}`, - ); - } + typedEntries(proposedEntitiesByType).map<[VersionedUrl, DeprecatedProposedEntity[]]>( + ([simplifiedEntityTypeId, entities]) => { + const entityTypeId = simplifiedEntityTypeIdMappings[simplifiedEntityTypeId]; + + if (!entityTypeId) { + throw new Error( + `Could not find entity type id for simplified entity type id ${simplifiedEntityTypeId}`, + ); + } - return [ - entityTypeId, - entities - .filter( - ({ entityId }) => - // Don't include invalid entities - !invalidProposedEntities.some( - ({ - invalidProposedEntity: { entityId: invalidEntityId }, - }) => invalidEntityId === entityId, - ) && - // Ignore entities we've inferred in a previous iteration, otherwise we'll get duplicates - !inferenceState.proposedEntityCreationsByType[ - entityTypeId - ]?.some( - (existingEntity) => - existingEntity.entityId === entityId, - ), - ) - .map( - ({ - properties: simplifiedProperties, - ...proposedEntity - }) => { - const { simplifiedPropertyTypeMappings } = - entityTypes[entityTypeId] ?? {}; + return [ + entityTypeId, + entities + .filter( + ({ entityId }) => + // Don't include invalid entities + !invalidProposedEntities.some( + ({ invalidProposedEntity: { entityId: invalidEntityId } }) => + invalidEntityId === entityId, + ) && + // Ignore entities we've inferred in a previous iteration, otherwise we'll get duplicates + !inferenceState.proposedEntityCreationsByType[entityTypeId]?.some( + (existingEntity) => existingEntity.entityId === entityId, + ), + ) + .map(({ properties: simplifiedProperties, ...proposedEntity }) => { + const { simplifiedPropertyTypeMappings } = entityTypes[entityTypeId] ?? {}; if (!simplifiedPropertyTypeMappings) { throw new Error( @@ -537,117 +490,105 @@ export const proposeEntities = async (params: { ...proposedEntity, properties, }; - }, - ), - ]; - }), + }), + ]; + }, + ), ); - const validProposedEntities = Object.values( - validProposedEntitiesByType, - ).flat(); + const validProposedEntities = Object.values(validProposedEntitiesByType).flat(); const now = new Date().toISOString(); if (validProposedEntities.length > 0) { logProgress( - typedEntries(validProposedEntitiesByType).flatMap( - ([entityTypeId, entities]) => - entities.map((entity) => ({ - isUpdateToExistingProposal: false, - proposedEntity: { - ...entity, - claims: { - isSubjectOf: [], - isObjectOf: [], - }, - localEntityId: entityIdFromComponents( - webId, - /** - * @todo H-3163: this is not a valid UUID, but it's only used in a progress log so won't be used - * as the entity's UUID when persisting it. this file in its entirety will be removed as part of H-3163 - * when we migrate the browser plugin flows to use the same claims -> entity process as other flows. - * The same applies to the sourceEntityId and targetEntityId below. - */ - entity.entityId.toString() as EntityUuid, - ), - entityTypeIds: [entityTypeId as VersionedUrl], - properties: entity.properties ?? {}, - propertyMetadata: { value: {} }, - sourceEntityId: - "sourceEntityId" in entity - ? { - kind: "proposed-entity", - localId: entityIdFromComponents( - webId, - entity.sourceEntityId.toString() as EntityUuid, - ), - } - : undefined, - targetEntityId: - "targetEntityId" in entity - ? { - kind: "proposed-entity", - localId: entityIdFromComponents( - webId, - entity.targetEntityId.toString() as EntityUuid, - ), - } - : undefined, + typedEntries(validProposedEntitiesByType).flatMap(([entityTypeId, entities]) => + entities.map((entity) => ({ + isUpdateToExistingProposal: false, + proposedEntity: { + ...entity, + claims: { + isSubjectOf: [], + isObjectOf: [], }, - recordedAt: now, - type: "ProposedEntity", - stepId: Context.current().info.activityId, - workerType: "Link explorer", - parentInstanceId: null, - workerInstanceId: "browser-plugin-flow", - toolCallId: null, - })), + localEntityId: entityIdFromComponents( + webId, + /** + * @todo H-3163: this is not a valid UUID, but it's only used in a progress log so won't be used + * as the entity's UUID when persisting it. this file in its entirety will be removed as part of H-3163 + * when we migrate the browser plugin flows to use the same claims -> entity process as other flows. + * The same applies to the sourceEntityId and targetEntityId below. + */ + entity.entityId.toString() as EntityUuid, + ), + entityTypeIds: [entityTypeId as VersionedUrl], + properties: entity.properties ?? {}, + propertyMetadata: { value: {} }, + sourceEntityId: + "sourceEntityId" in entity + ? { + kind: "proposed-entity", + localId: entityIdFromComponents( + webId, + entity.sourceEntityId.toString() as EntityUuid, + ), + } + : undefined, + targetEntityId: + "targetEntityId" in entity + ? { + kind: "proposed-entity", + localId: entityIdFromComponents( + webId, + entity.targetEntityId.toString() as EntityUuid, + ), + } + : undefined, + }, + recordedAt: now, + type: "ProposedEntity", + stepId: Context.current().info.activityId, + workerType: "Link explorer", + parentInstanceId: null, + workerInstanceId: "browser-plugin-flow", + toolCallId: null, + })), ), ); } - logger.info( - `Proposed ${validProposedEntities.length} valid additional entities.`, - ); - logger.info( - `Proposed ${invalidProposedEntities.length} invalid additional entities.`, - ); + logger.info(`Proposed ${validProposedEntities.length} valid additional entities.`); + logger.info(`Proposed ${invalidProposedEntities.length} invalid additional entities.`); /** * Remove the valid entities from the list of entities in progress. */ - inferenceState.inProgressEntityIds = - inferenceState.inProgressEntityIds.filter( - (inProgressEntityId) => - !validProposedEntities.some( - ({ entityId }) => entityId === inProgressEntityId, - ), - ); + inferenceState.inProgressEntityIds = inferenceState.inProgressEntityIds.filter( + (inProgressEntityId) => + !validProposedEntities.some(({ entityId }) => entityId === inProgressEntityId), + ); /** * The agent may have inferred valid entities that we didn't yet ask it for, * in which case we need to mark them as taken from the queue so we don't * ask for them again. */ - inferenceState.proposedEntitySummaries = - inferenceState.proposedEntitySummaries.map( - (proposedEntitySummary) => { - if ( - !proposedEntitySummary.takenFromQueue && - validProposedEntities.some( - ({ entityId }) => - entityId === proposedEntitySummary.entityId, - ) - ) { - return { - ...proposedEntitySummary, - takenFromQueue: true, - }; - } - return proposedEntitySummary; - }, - ); + inferenceState.proposedEntitySummaries = inferenceState.proposedEntitySummaries.map( + (proposedEntitySummary) => { + if ( + !proposedEntitySummary.takenFromQueue && + validProposedEntities.some( + ({ entityId }) => entityId === proposedEntitySummary.entityId, + ) + ) { + return { + ...proposedEntitySummary, + takenFromQueue: true, + }; + } + return proposedEntitySummary; + }, + ); inferenceState.proposedEntityCreationsByType = Object.entries( validProposedEntitiesByType, @@ -673,14 +614,11 @@ export const proposeEntities = async (params: { } const remainingEntitySummaries = - inferenceState.proposedEntitySummaries.filter( - (entity) => !entity.takenFromQueue, - ).length + inferenceState.inProgressEntityIds.length; + inferenceState.proposedEntitySummaries.filter((entity) => !entity.takenFromQueue).length + + inferenceState.inProgressEntityIds.length; if (remainingEntitySummaries > 0) { - logger.info( - `${remainingEntitySummaries} entities remain to be inferred, continuing.`, - ); + logger.info(`${remainingEntitySummaries} entities remain to be inferred, continuing.`); retryMessageContent.push({ type: "text", text: "There are other entities you haven't yet provided details for", @@ -690,9 +628,7 @@ export const proposeEntities = async (params: { if (retryMessageContent.length === 0) { logger.info( - `Returning proposed entities: ${stringify( - inferenceState.proposedEntityCreationsByType, - )}`, + `Returning proposed entities: ${stringify(inferenceState.proposedEntityCreationsByType)}`, ); return { diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/extract-validation-failure-details.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/extract-validation-failure-details.ts index 81e3e055cfe..0acc86e588d 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/extract-validation-failure-details.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/extract-validation-failure-details.ts @@ -1,7 +1,6 @@ import { stringifyError } from "@local/hash-isomorphic-utils/stringify-error"; -const isTrueObject = (obj: unknown): obj is object => - obj !== null && typeof obj === "object"; +const isTrueObject = (obj: unknown): obj is object => obj !== null && typeof obj === "object"; type ContextObject = { context: string; diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-propose-entities-tools.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-propose-entities-tools.ts index 42aada01e94..311e76f8b6a 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-propose-entities-tools.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-propose-entities-tools.ts @@ -53,8 +53,7 @@ export const generateProposeEntitiesTools = (params: { const { entityTypes } = params; let simplifiedEntityTypeIdMappings: Record = {}; - const reverseSimplifiedEntityTypeIdMappings: Record = - {}; + const reverseSimplifiedEntityTypeIdMappings: Record = {}; const tools: LlmToolDefinition[] = [ { name: "create_entities", @@ -62,69 +61,62 @@ export const generateProposeEntitiesTools = (params: { inputSchema: { type: "object", additionalProperties: false, - properties: entityTypes.reduce>( - (acc, { schema, isLink }) => { - const entityTypeId = schema.$id; + properties: entityTypes.reduce>((acc, { schema, isLink }) => { + const entityTypeId = schema.$id; - const { - simplifiedTypeId: simplifiedEntityTypeId, - updatedTypeMappings, - } = generateSimplifiedTypeId({ + const { simplifiedTypeId: simplifiedEntityTypeId, updatedTypeMappings } = + generateSimplifiedTypeId({ title: schema.title, typeIdOrBaseUrl: entityTypeId, existingTypeMappings: simplifiedEntityTypeIdMappings, - existingReverseTypeMappings: - reverseSimplifiedEntityTypeIdMappings, + existingReverseTypeMappings: reverseSimplifiedEntityTypeIdMappings, }); - simplifiedEntityTypeIdMappings = updatedTypeMappings; + simplifiedEntityTypeIdMappings = updatedTypeMappings; - /** - * @todo H-2241 support proposing entities with multiple types, or remove this code (used by the browser plugin) - * in favour of propose-entities-from-claims - */ - acc[simplifiedEntityTypeId] = { - type: "array", - title: `${schema.title} entities to create`, - items: { - type: "object", - additionalProperties: false, - title: schema.title, - description: schema.description, + /** + * @todo H-2241 support proposing entities with multiple types, or remove this code (used by the browser plugin) + * in favour of propose-entities-from-claims + */ + acc[simplifiedEntityTypeId] = { + type: "array", + title: `${schema.title} entities to create`, + items: { + type: "object", + additionalProperties: false, + title: schema.title, + description: schema.description, + properties: { + entityId: { + description: + "Your numerical identifier for the entity, unique among the inferred entities in this conversation", + type: "number", + }, + ...(isLink ? generateToolLinkFields() : {}), properties: { - entityId: { - description: - "Your numerical identifier for the entity, unique among the inferred entities in this conversation", - type: "number", - }, - ...(isLink ? generateToolLinkFields() : {}), - properties: { - description: "The properties to set on the entity", - default: {}, - type: "object", - additionalProperties: false, - properties: stripIdsFromDereferencedProperties({ - properties: schema.properties, - }), - }, - } satisfies ProposedEntitySchemaOrData, - required: [ - "entityId", - "properties", - ...(isLink ? ["sourceEntityId", "targetEntityId"] : []), - ], - }, - }; - return acc; - }, - {}, - ), + description: "The properties to set on the entity", + default: {}, + type: "object", + additionalProperties: false, + properties: stripIdsFromDereferencedProperties({ + properties: schema.properties, + }), + }, + } satisfies ProposedEntitySchemaOrData, + required: [ + "entityId", + "properties", + ...(isLink ? ["sourceEntityId", "targetEntityId"] : []), + ], + }, + }; + return acc; + }, {}), }, }, { name: "abandon_entities", - description: - "Give up trying to create, following failures which you cannot correct", + description: "Give up trying to create, following failures which you cannot correct", inputSchema: { type: "object", additionalProperties: false, diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-simplified-type-id.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-simplified-type-id.ts index 125b763d7e4..2140a3d5773 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-simplified-type-id.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/generate-simplified-type-id.ts @@ -1,9 +1,6 @@ import type { BaseUrl, VersionedUrl } from "@blockprotocol/type-system"; -export const generateSimplifiedTypeIdFromTitle = (params: { - title: string; - postfix?: string; -}) => { +export const generateSimplifiedTypeIdFromTitle = (params: { title: string; postfix?: string }) => { const { title, postfix } = params; /** @@ -28,12 +25,7 @@ export const generateSimplifiedTypeId = < updatedTypeMappings: Record; updatedReverseTypeMappings: Record; } => { - const { - title, - typeIdOrBaseUrl, - existingTypeMappings, - existingReverseTypeMappings, - } = params; + const { title, typeIdOrBaseUrl, existingTypeMappings, existingReverseTypeMappings } = params; let counter = 1; if (existingReverseTypeMappings[typeIdOrBaseUrl]) { diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/map-simplified-properties-to-properties.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/map-simplified-properties-to-properties.ts index b536a2419b1..0b9c82c30ea 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/map-simplified-properties-to-properties.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/map-simplified-properties-to-properties.ts @@ -1,8 +1,4 @@ -import type { - BaseUrl, - PropertyObject, - PropertyValue, -} from "@blockprotocol/type-system"; +import type { BaseUrl, PropertyObject, PropertyValue } from "@blockprotocol/type-system"; import type { HashEntity } from "@local/hash-graph-sdk/entity"; export type PropertyValueWithSimplifiedProperties = @@ -19,10 +15,7 @@ const mapSimplifiedPropertyValueToPropertyValue = (params: { }): HashEntity["properties"][BaseUrl] => { const { simplifiedPropertyValue, simplifiedPropertyTypeMappings } = params; - if ( - typeof simplifiedPropertyValue !== "object" || - simplifiedPropertyValue === null - ) { + if (typeof simplifiedPropertyValue !== "object" || simplifiedPropertyValue === null) { return simplifiedPropertyValue; } diff --git a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/strip-ids-from-dereferenced-properties.ts b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/strip-ids-from-dereferenced-properties.ts index 585fbf2468d..903834ea57a 100644 --- a/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/strip-ids-from-dereferenced-properties.ts +++ b/apps/hash-ai-worker-ts/src/activities/infer-entities/shared/strip-ids-from-dereferenced-properties.ts @@ -31,10 +31,7 @@ export const stripIdsFromDereferencedProperties = (params: { items: { ...itemsWithoutId, oneOf: itemsWithoutId.oneOf.map((oneOfValue) => { - if ( - typeof oneOfValue === "object" && - "properties" in oneOfValue - ) { + if (typeof oneOfValue === "object" && "properties" in oneOfValue) { return { ...oneOfValue, properties: stripIdsFromDereferencedProperties({ diff --git a/apps/hash-ai-worker-ts/src/activities/parse-text-from-file.ts b/apps/hash-ai-worker-ts/src/activities/parse-text-from-file.ts index 961239b4bc2..1de8d233ac4 100644 --- a/apps/hash-ai-worker-ts/src/activities/parse-text-from-file.ts +++ b/apps/hash-ai-worker-ts/src/activities/parse-text-from-file.ts @@ -20,25 +20,16 @@ import type { TextualContentPropertyValueWithMetadata } from "@local/hash-isomor type TextParsingFunction = (fileBuffer: Buffer) => Promise; -const officeParserTextParsingFunction: TextParsingFunction = async ( - fileBuffer, -) => { - const text = await officeParser - .parseOffice(fileBuffer) - .then((ast) => ast.toText()); +const officeParserTextParsingFunction: TextParsingFunction = async (fileBuffer) => { + const text = await officeParser.parseOffice(fileBuffer).then((ast) => ast.toText()); return text; }; -const fileEntityTypeToParsingFunction: Record< - VersionedUrl, - TextParsingFunction -> = { - [systemEntityTypes.docxDocument.entityTypeId]: - officeParserTextParsingFunction, +const fileEntityTypeToParsingFunction: Record = { + [systemEntityTypes.docxDocument.entityTypeId]: officeParserTextParsingFunction, [systemEntityTypes.pdfDocument.entityTypeId]: officeParserTextParsingFunction, - [systemEntityTypes.pptxPresentation.entityTypeId]: - officeParserTextParsingFunction, + [systemEntityTypes.pptxPresentation.entityTypeId]: officeParserTextParsingFunction, }; export const parseTextFromFile = async ( @@ -80,14 +71,11 @@ export const parseTextFromFile = async ( propertyPatches: [ { op: "add", - path: [ - blockProtocolPropertyTypes.textualContent.propertyTypeBaseUrl, - ], + path: [blockProtocolPropertyTypes.textualContent.propertyTypeBaseUrl], property: { value: textualContent, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, } satisfies TextualContentPropertyValueWithMetadata, }, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/activity-logger.ts b/apps/hash-ai-worker-ts/src/activities/shared/activity-logger.ts index 355944ac57e..deddad6864c 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/activity-logger.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/activity-logger.ts @@ -76,10 +76,7 @@ const log = ( fs.mkdirSync(logFolderPath); } - const logFilePath = path.join( - logFolderPath, - `${workflowExecution.workflowId}.log`, - ); + const logFilePath = path.join(logFolderPath, `${workflowExecution.workflowId}.log`); let stringifiedMessage: string; @@ -93,8 +90,7 @@ const log = ( // the flow-level log. const filtered = safeStringify(restMeta, { space: 2, - replacer: (key, value) => - detailedFields?.includes(key) ? undefined : value, + replacer: (key, value) => (detailedFields?.includes(key) ? undefined : value), }); // File name already encodes the flow id, so no prefix needed here. diff --git a/apps/hash-ai-worker-ts/src/activities/shared/create-inferred-entity-notification.ts b/apps/hash-ai-worker-ts/src/activities/shared/create-inferred-entity-notification.ts index 988251e5cfb..b3bf045086c 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/create-inferred-entity-notification.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/create-inferred-entity-notification.ts @@ -16,9 +16,7 @@ export const createInferredEntityNotification = async ({ operation: "create" | "update"; notifiedUserAccountId: UserId; }) => { - const entityIsDraft = !!extractDraftIdFromEntityId( - entity.metadata.recordId.entityId, - ); + const entityIsDraft = !!extractDraftIdFromEntityId(entity.metadata.recordId.entityId); if (entityIsDraft) { /** @@ -27,8 +25,7 @@ export const createInferredEntityNotification = async ({ return; } - const entityEditionTimestamp = - entity.metadata.temporalVersioning.decisionTime.start.limit; + const entityEditionTimestamp = entity.metadata.temporalVersioning.decisionTime.start.limit; await createGraphChangeNotification( { graphApi: graphApiClient }, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.test.ts b/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.test.ts index b70012f26c7..a0725682ea2 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.test.ts @@ -39,8 +39,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/", revisionId: "1", }, }, @@ -48,8 +47,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/number/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/number/", revisionId: "1", }, }, @@ -61,8 +59,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/", revisionId: "1", }, }, @@ -74,8 +71,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/", revisionId: "1", }, }, @@ -131,8 +127,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_PROPERTIES_ON", reversed: false, rightEndpoint: { - baseId: - "https://hash.ai/@test/types/property-type/notes-and-summary/", + baseId: "https://hash.ai/@test/types/property-type/notes-and-summary/", revisionId: "1", }, }, @@ -144,8 +139,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/", revisionId: "1", }, }, @@ -157,8 +151,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/", revisionId: "1", }, }, @@ -170,8 +163,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/", revisionId: "1", }, }, @@ -183,8 +175,7 @@ const testSubgraph: Pick = { kind: "CONSTRAINS_VALUES_ON", reversed: false, rightEndpoint: { - baseId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/", + baseId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/", revisionId: "1", }, }, @@ -203,8 +194,7 @@ const testSubgraph: Pick = { kind: "dataType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/data-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/data-type", kind: "dataType", $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", title: "Text", @@ -213,8 +203,7 @@ const testSubgraph: Pick = { }, metadata: { recordId: { - baseUrl: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/", + baseUrl: "https://blockprotocol.org/@blockprotocol/types/data-type/text/", version: "1", }, provenance: { @@ -247,13 +236,11 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@test/types/property-type/notes-and-summary/v/1", title: "Notes And Summary", - description: - "A property object which contains an array of notes, and a summary", + description: "A property object which contains an array of notes, and a summary", oneOf: [ { type: "object", @@ -273,8 +260,7 @@ const testSubgraph: Pick = { }, metadata: { recordId: { - baseUrl: - "https://hash.ai/@test/types/property-type/notes-and-summary/", + baseUrl: "https://hash.ai/@test/types/property-type/notes-and-summary/", version: "1", }, provenance: { @@ -307,13 +293,11 @@ const testSubgraph: Pick = { kind: "entityType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/entity-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/entity-type", kind: "entityType", $id: "https://hash.ai/@test/types/entity-type/property-values-demo/v/4", title: "Property Values Demo", - description: - "A type with various permutations of expected property value types", + description: "A type with various permutations of expected property value types", type: "object", properties: { "https://hash.ai/@h/types/property-type/deleted-at/": { @@ -349,8 +333,7 @@ const testSubgraph: Pick = { }, metadata: { recordId: { - baseUrl: - "https://hash.ai/@test/types/entity-type/property-values-demo/", + baseUrl: "https://hash.ai/@test/types/entity-type/property-values-demo/", version: "4", }, provenance: { @@ -383,8 +366,7 @@ const testSubgraph: Pick = { kind: "dataType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/data-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/data-type", kind: "dataType", $id: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", title: "Number", @@ -393,8 +375,7 @@ const testSubgraph: Pick = { }, metadata: { recordId: { - baseUrl: - "https://blockprotocol.org/@blockprotocol/types/data-type/number/", + baseUrl: "https://blockprotocol.org/@blockprotocol/types/data-type/number/", version: "1", }, provenance: { @@ -427,8 +408,7 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@test/types/property-type/mixed-array/v/3", title: "Mixed Array", @@ -524,8 +504,7 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@h/types/property-type/archived/v/1", title: "Archived", @@ -571,8 +550,7 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@h/types/property-type/expired-at/v/1", title: "Expired At", @@ -618,8 +596,7 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@h/types/property-type/summary/v/1", title: "Summary", @@ -665,8 +642,7 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@h/types/property-type/organization-name/v/1", title: "Organization Name", @@ -679,8 +655,7 @@ const testSubgraph: Pick = { }, metadata: { recordId: { - baseUrl: - "https://hash.ai/@h/types/property-type/organization-name/", + baseUrl: "https://hash.ai/@h/types/property-type/organization-name/", version: "1", }, provenance: { @@ -713,8 +688,7 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@h/types/property-type/deleted-at/v/1", title: "Deleted At", @@ -760,8 +734,7 @@ const testSubgraph: Pick = { kind: "dataType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/data-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/data-type", kind: "dataType", $id: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", title: "Boolean", @@ -770,8 +743,7 @@ const testSubgraph: Pick = { }, metadata: { recordId: { - baseUrl: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/", + baseUrl: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/", version: "1", }, provenance: { @@ -804,8 +776,7 @@ const testSubgraph: Pick = { kind: "propertyType", inner: { schema: { - $schema: - "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", + $schema: "https://blockprotocol.org/types/modules/graph/0.3/schema/property-type", kind: "propertyType", $id: "https://hash.ai/@d/types/property-type/notes/v/1", title: "Notes", @@ -851,15 +822,12 @@ const testSubgraph: Pick = { const expectedResult = { isLink: false, - parentIds: [ - "https://hash.ai/@test/types/entity-type/property-values-demo/v/4", - ], + parentIds: ["https://hash.ai/@test/types/entity-type/property-values-demo/v/4"], schema: { $id: "https://hash.ai/@test/types/entity-type/property-values-demo/v/4", additionalProperties: false, title: "Property Values Demo", - description: - "A type with various permutations of expected property value types", + description: "A type with various permutations of expected property value types", links: { "https://hash.ai/@h/types/entity-type/has-parent/v/1": { type: "array", @@ -894,8 +862,7 @@ const expectedResult = { "https://hash.ai/@test/types/property-type/notes-and-summary/": { $id: "https://hash.ai/@test/types/property-type/notes-and-summary/v/1", title: "Notes And Summary", - description: - "A property object which contains an array of notes, and a summary", + description: "A property object which contains an array of notes, and a summary", oneOf: [ { additionalProperties: false, @@ -957,8 +924,7 @@ const expectedResult = { oneOf: [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", - description: - "An arithmetical value (in the Real number system)", + description: "An arithmetical value (in the Real number system)", title: "Number", type: "number", }, @@ -970,8 +936,7 @@ const expectedResult = { items: { $id: "https://hash.ai/@h/types/property-type/expired-at/v/1", title: "Expired At", - description: - "Stringified timestamp of when something expired.", + description: "Stringified timestamp of when something expired.", oneOf: [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", @@ -985,8 +950,7 @@ const expectedResult = { "https://hash.ai/@h/types/property-type/archived/": { $id: "https://hash.ai/@h/types/property-type/archived/v/1", title: "Archived", - description: - "Whether or not something has been archived.", + description: "Whether or not something has been archived.", oneOf: [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", @@ -1004,8 +968,7 @@ const expectedResult = { oneOf: [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", - description: - "An arithmetical value (in the Real number system)", + description: "An arithmetical value (in the Real number system)", title: "Number", type: "number", }, @@ -1070,12 +1033,10 @@ describe("The dereferenceEntityType function", () => { it("correctly dereferences an entity type", () => { const { simplifiedPropertyTypeMappings: _simplifiedPropertyTypeMappings, - reverseSimplifiedPropertyTypeMappings: - _reverseSimplifiedPropertyTypeMappings, + reverseSimplifiedPropertyTypeMappings: _reverseSimplifiedPropertyTypeMappings, ...result } = dereferenceEntityType({ - entityTypeId: - "https://hash.ai/@test/types/entity-type/property-values-demo/v/4", + entityTypeId: "https://hash.ai/@test/types/entity-type/property-values-demo/v/4", subgraph: { ...testSubgraph, vertices: mapGraphApiVerticesToVertices(testSubgraph.vertices), diff --git a/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.ts b/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.ts index 4d5d861d382..490e9598742 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/dereference-entity-type.ts @@ -32,19 +32,16 @@ import type { DistributiveOmit } from "@local/advanced-types/distribute"; type MinimalDataType = DistributiveOmit; -export type MinimalPropertyObject = PropertyValueObject< - ValueOrArray -> & { additionalProperties: false }; +export type MinimalPropertyObject = PropertyValueObject> & { + additionalProperties: false; +}; export type MinimalPropertyTypeValue = | MinimalDataType | MinimalPropertyObject | PropertyValueArray>; -export type DereferencedPropertyType = Pick< - PropertyType, - "$id" | "description" | "title" -> & +export type DereferencedPropertyType = Pick & OneOfSchema; /** @@ -53,9 +50,7 @@ export type DereferencedPropertyType = Pick< * If the dereference function is called with `simplifyPropertyKeys` set to `true`, the property keys in the schema * will be simplified from BaseUrls to simple strings. The mapping back to BaseUrls is returned from the function */ -export type DereferencedEntityType< - PropertyTypeKey extends string | BaseUrl = BaseUrl, -> = Pick< +export type DereferencedEntityType = Pick< EntityType, "$id" | "description" | "links" | "required" | "title" | "labelProperty" > & { @@ -87,10 +82,8 @@ const dereferencePropertyTypeValue = (params: { } => { const { valueReference, subgraph, simplifyPropertyKeys } = params; - let simplifiedPropertyTypeMappings = - params.existingSimplifiedPropertyTypeMappings; - let reverseSimplifiedPropertyTypeMappings = - params.existingReverseSimplifiedPropertyTypeMappings; + let simplifiedPropertyTypeMappings = params.existingSimplifiedPropertyTypeMappings; + let reverseSimplifiedPropertyTypeMappings = params.existingReverseSimplifiedPropertyTypeMappings; const isArray = "items" in valueReference; @@ -106,18 +99,14 @@ const dereferencePropertyTypeValue = (params: { } = dereferencePropertyTypeValue({ valueReference: arrayValueReference, subgraph, - existingSimplifiedPropertyTypeMappings: - simplifiedPropertyTypeMappings, - existingReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + existingSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, + existingReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, simplifyPropertyKeys, }); - simplifiedPropertyTypeMappings = - updatedSimplifiedPropertyTypeMappings; + simplifiedPropertyTypeMappings = updatedSimplifiedPropertyTypeMappings; - reverseSimplifiedPropertyTypeMappings = - updatedReverseSimplifiedPropertyTypeMappings; + reverseSimplifiedPropertyTypeMappings = updatedReverseSimplifiedPropertyTypeMappings; return propertyValue; }) as [MinimalPropertyTypeValue, ...MinimalPropertyTypeValue[]], @@ -127,8 +116,7 @@ const dereferencePropertyTypeValue = (params: { type: "array", }, updatedSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, - updatedReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + updatedReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, }; } @@ -147,9 +135,7 @@ const dereferencePropertyTypeValue = (params: { const propertyType = getPropertyTypeById(subgraph, propertyTypeId); if (!propertyType) { - throw new Error( - `Could not find property with id ${propertyTypeId}`, - ); + throw new Error(`Could not find property with id ${propertyTypeId}`); } const { @@ -159,32 +145,25 @@ const dereferencePropertyTypeValue = (params: { } = dereferencePropertyType({ propertyTypeId: propertyType.schema.$id, subgraph, - existingSimplifiedPropertyTypeMappings: - simplifiedPropertyTypeMappings, - existingReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + existingSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, + existingReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, simplifyPropertyKeys, }); - simplifiedPropertyTypeMappings = - updatedSimplifiedPropertyTypeMappings; + simplifiedPropertyTypeMappings = updatedSimplifiedPropertyTypeMappings; const propertyTypeBaseUrl = extractBaseUrl(propertyType.schema.$id); let propertyKey: BaseUrl = propertyTypeBaseUrl; if (simplifyPropertyKeys) { - const { - simplifiedTypeId, - updatedTypeMappings, - updatedReverseTypeMappings, - } = generateSimplifiedTypeId({ - title: propertyType.schema.title, - typeIdOrBaseUrl: propertyTypeBaseUrl, - existingTypeMappings: simplifiedPropertyTypeMappings, - existingReverseTypeMappings: - reverseSimplifiedPropertyTypeMappings, - }); + const { simplifiedTypeId, updatedTypeMappings, updatedReverseTypeMappings } = + generateSimplifiedTypeId({ + title: propertyType.schema.title, + typeIdOrBaseUrl: propertyTypeBaseUrl, + existingTypeMappings: simplifiedPropertyTypeMappings, + existingReverseTypeMappings: reverseSimplifiedPropertyTypeMappings, + }); propertyKey = simplifiedTypeId as BaseUrl; @@ -207,11 +186,8 @@ const dereferencePropertyTypeValue = (params: { ? valueReference.required ? atLeastOne( valueReference.required.map((requiredPropertyBaseUrl) => { - const simplifiedPropertyId = Object.entries( - simplifiedPropertyTypeMappings, - ).find( - ([_, propertyBaseUrl]) => - propertyBaseUrl === requiredPropertyBaseUrl, + const simplifiedPropertyId = Object.entries(simplifiedPropertyTypeMappings).find( + ([_, propertyBaseUrl]) => propertyBaseUrl === requiredPropertyBaseUrl, )?.[0] as BaseUrl | undefined; return simplifiedPropertyId ?? requiredPropertyBaseUrl; @@ -223,30 +199,21 @@ const dereferencePropertyTypeValue = (params: { type: "object", }, updatedSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, - updatedReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + updatedReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, }; } const dataType = getDataTypeById(subgraph, valueReference.$ref); if (!dataType) { - throw new Error( - `Could not find data type with id ${valueReference.$ref} in subgraph`, - ); + throw new Error(`Could not find data type with id ${valueReference.$ref} in subgraph`); } - const { - $schema: _$schema, - kind: _kind, - allOf: _allOf, - ...minimalDataType - } = dataType.schema; + const { $schema: _$schema, kind: _kind, allOf: _allOf, ...minimalDataType } = dataType.schema; return { propertyValue: minimalDataType, updatedSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, - updatedReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + updatedReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, }; }; @@ -263,10 +230,8 @@ const dereferencePropertyType = (params: { } => { const { propertyTypeId, subgraph, simplifyPropertyKeys } = params; - let simplifiedPropertyTypeMappings = - params.existingSimplifiedPropertyTypeMappings; - let reverseSimplifiedPropertyTypeMappings = - params.existingReverseSimplifiedPropertyTypeMappings; + let simplifiedPropertyTypeMappings = params.existingSimplifiedPropertyTypeMappings; + let reverseSimplifiedPropertyTypeMappings = params.existingReverseSimplifiedPropertyTypeMappings; const propertyType = getPropertyTypeById(subgraph, propertyTypeId); @@ -283,14 +248,12 @@ const dereferencePropertyType = (params: { valueReference: reference, subgraph, existingSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, - existingReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + existingReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, simplifyPropertyKeys, }); simplifiedPropertyTypeMappings = updatedSimplifiedPropertyTypeMappings; - reverseSimplifiedPropertyTypeMappings = - updatedReverseSimplifiedPropertyTypeMappings; + reverseSimplifiedPropertyTypeMappings = updatedReverseSimplifiedPropertyTypeMappings; return propertyValue; }) as [MinimalPropertyTypeValue, ...MinimalPropertyTypeValue[]]; @@ -303,8 +266,7 @@ const dereferencePropertyType = (params: { oneOf: permittedValues, }, updatedSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, - updatedReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + updatedReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, }; }; @@ -313,9 +275,7 @@ type DererencedEntityTypeWithMappings< > = { isLink: boolean; parentIds: VersionedUrl[]; - schema: DereferencedEntityType< - SimplifyPropertyKeys extends true ? string : BaseUrl - >; + schema: DereferencedEntityType; simplifiedPropertyTypeMappings: Record; reverseSimplifiedPropertyTypeMappings: Record; }; @@ -344,20 +304,14 @@ export const dereferenceEntityType = < let simplifiedPropertyTypeMappings: Record = {}; let reverseSimplifiedPropertyTypeMappings: Record = {}; - const entityTypeWithAncestors = getEntityTypeAndParentsById( - subgraph, - entityTypeId, - ); + const entityTypeWithAncestors = getEntityTypeAndParentsById(subgraph, entityTypeId); const isLink = entityTypeWithAncestors.some( - (entityType) => - entityType.schema.$id === blockProtocolEntityTypes.link.entityTypeId, + (entityType) => entityType.schema.$id === blockProtocolEntityTypes.link.entityTypeId, ); let labelProperty: BaseUrl | undefined; - const mergedProperties: DereferencedEntityType< - string | BaseUrl - >["properties"] = {}; + const mergedProperties: DereferencedEntityType["properties"] = {}; const requiredProperties: Set = new Set(); @@ -374,13 +328,9 @@ export const dereferenceEntityType = < labelProperty = entityType.schema.labelProperty; } - for (const propertyRefSchema of Object.values( - entityType.schema.properties, - )) { + for (const propertyRefSchema of Object.values(entityType.schema.properties)) { const isArray = "items" in propertyRefSchema; - const propertyTypeId = isArray - ? propertyRefSchema.items.$ref - : propertyRefSchema.$ref; + const propertyTypeId = isArray ? propertyRefSchema.items.$ref : propertyRefSchema.$ref; const { baseUrl, version } = componentsFromVersionedUrl(propertyTypeId); @@ -399,9 +349,7 @@ export const dereferenceEntityType = < !existingProperty || compareOntologyTypeVersions( extractVersion( - "items" in existingProperty - ? existingProperty.items.$id - : existingProperty.$id, + "items" in existingProperty ? existingProperty.items.$id : existingProperty.$id, ), version, ) < 0 @@ -412,21 +360,16 @@ export const dereferenceEntityType = < const propertyType = getPropertyTypeById(subgraph, propertyTypeId); if (!propertyType) { - throw new Error( - `Could not find property with id ${propertyTypeId}`, - ); + throw new Error(`Could not find property with id ${propertyTypeId}`); } - const { - simplifiedTypeId, - updatedTypeMappings, - updatedReverseTypeMappings, - } = generateSimplifiedTypeId({ - title: propertyType.schema.title, - typeIdOrBaseUrl: baseUrl, - existingTypeMappings: simplifiedPropertyTypeMappings, - existingReverseTypeMappings: reverseSimplifiedPropertyTypeMappings, - }); + const { simplifiedTypeId, updatedTypeMappings, updatedReverseTypeMappings } = + generateSimplifiedTypeId({ + title: propertyType.schema.title, + typeIdOrBaseUrl: baseUrl, + existingTypeMappings: simplifiedPropertyTypeMappings, + existingReverseTypeMappings: reverseSimplifiedPropertyTypeMappings, + }); simplifiedPropertyTypeMappings = updatedTypeMappings; reverseSimplifiedPropertyTypeMappings = updatedReverseTypeMappings; @@ -441,16 +384,13 @@ export const dereferenceEntityType = < } = dereferencePropertyType({ propertyTypeId, subgraph, - existingSimplifiedPropertyTypeMappings: - simplifiedPropertyTypeMappings, - existingReverseSimplifiedPropertyTypeMappings: - reverseSimplifiedPropertyTypeMappings, + existingSimplifiedPropertyTypeMappings: simplifiedPropertyTypeMappings, + existingReverseSimplifiedPropertyTypeMappings: reverseSimplifiedPropertyTypeMappings, simplifyPropertyKeys, }); simplifiedPropertyTypeMappings = updatedSimplifiedPropertyTypeMappings; - reverseSimplifiedPropertyTypeMappings = - updatedReverseSimplifiedPropertyTypeMappings; + reverseSimplifiedPropertyTypeMappings = updatedReverseSimplifiedPropertyTypeMappings; mergedProperties[propertyKey] = isArray ? { ...propertyRefSchema, items: dereferencedPropertyType } @@ -461,9 +401,7 @@ export const dereferenceEntityType = < const mergedLinks: DereferencedEntityType["links"] = {}; for (const entityType of entityTypeWithAncestors) { - for (const [versionedUrl, linkSchema] of typedEntries( - entityType.schema.links ?? {}, - )) { + for (const [versionedUrl, linkSchema] of typedEntries(entityType.schema.links ?? {})) { mergedLinks[versionedUrl] ??= linkSchema; } } @@ -475,30 +413,29 @@ export const dereferenceEntityType = < ); } - const mergedSchema: DereferencedEntityType< - SimplifyPropertyKeys extends true ? string : BaseUrl - > = { - $id: entityType.schema.$id, - title: entityType.schema.title, - description: entityType.schema.description, - labelProperty, - links: mergedLinks, - properties: mergedProperties, - additionalProperties: false, - required: atLeastOne( - simplifyPropertyKeys - ? [...requiredProperties].map((baseUrl) => { - const simpleTitle = reverseSimplifiedPropertyTypeMappings[baseUrl]; - - if (!simpleTitle) { - throw new Error(`Could not find simplified title for ${baseUrl}`); - } - - return simpleTitle as BaseUrl; - }) - : [...requiredProperties], - ), - }; + const mergedSchema: DereferencedEntityType = + { + $id: entityType.schema.$id, + title: entityType.schema.title, + description: entityType.schema.description, + labelProperty, + links: mergedLinks, + properties: mergedProperties, + additionalProperties: false, + required: atLeastOne( + simplifyPropertyKeys + ? [...requiredProperties].map((baseUrl) => { + const simpleTitle = reverseSimplifiedPropertyTypeMappings[baseUrl]; + + if (!simpleTitle) { + throw new Error(`Could not find simplified title for ${baseUrl}`); + } + + return simpleTitle as BaseUrl; + }) + : [...requiredProperties], + ), + }; return { isLink, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/embeddings.ts b/apps/hash-ai-worker-ts/src/activities/shared/embeddings.ts index 82d44e7e0e4..5caeab93288 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/embeddings.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/embeddings.ts @@ -59,9 +59,7 @@ export const createEntityEmbeddings = async (params: { usage: Usage; }> => { // sort property types by their base url - params.propertyTypes.sort((a, b) => - extractBaseUrl(a.$id).localeCompare(extractBaseUrl(b.$id)), - ); + params.propertyTypes.sort((a, b) => extractBaseUrl(a.$id).localeCompare(extractBaseUrl(b.$id))); // We want to create embeddings for: // 1. Each individual '[Property Title]: [Value]' pair, and diff --git a/apps/hash-ai-worker-ts/src/activities/shared/find-existing-entity.ts b/apps/hash-ai-worker-ts/src/activities/shared/find-existing-entity.ts index 662cbcbb422..7eb18dcabaf 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/find-existing-entity.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/find-existing-entity.ts @@ -16,23 +16,11 @@ import { deduplicateSources } from "@local/hash-isomorphic-utils/provenance"; import { logger } from "./activity-logger.js"; import { dereferenceEntityType } from "./dereference-entity-type.js"; import { createEntityEmbeddings } from "./embeddings.js"; -import { - type MatchedEntityUpdate, - matchExistingEntity, -} from "./match-existing-entity.js"; +import { type MatchedEntityUpdate, matchExistingEntity } from "./match-existing-entity.js"; import type { DereferencedEntityType } from "./dereference-entity-type.js"; -import type { - ActorEntityUuid, - BaseUrl, - LinkData, - WebId, -} from "@blockprotocol/type-system"; -import type { - AllFilter, - CosineDistanceFilter, - GraphApi, -} from "@local/hash-graph-client"; +import type { ActorEntityUuid, BaseUrl, LinkData, WebId } from "@blockprotocol/type-system"; +import type { AllFilter, CosineDistanceFilter, GraphApi } from "@local/hash-graph-client"; import type { ProposedEntity } from "@local/hash-isomorphic-utils/flows/types"; export const findExistingEntity = async ({ @@ -99,14 +87,8 @@ export const findExistingEntity = async ({ entityProperties: proposedEntity.properties, propertyTypes: entityTypes.flatMap((entityType) => Object.values(entityType.properties).map((propertySchema) => ({ - title: - "items" in propertySchema - ? propertySchema.items.title - : propertySchema.title, - $id: - "items" in propertySchema - ? propertySchema.items.$id - : propertySchema.$id, + title: "items" in propertySchema ? propertySchema.items.title : propertySchema.title, + $id: "items" in propertySchema ? propertySchema.items.$id : propertySchema.$id, })), ), }); @@ -156,9 +138,7 @@ export const findExistingEntity = async ({ )) { if ( nameProperties.includes( - "items" in schema - ? schema.items.title.toLowerCase() - : schema.title.toLowerCase(), + "items" in schema ? schema.items.title.toLowerCase() : schema.title.toLowerCase(), ) && proposedEntity.properties[key] ) { @@ -187,9 +167,7 @@ export const findExistingEntity = async ({ ], }; } else { - logger.error( - `Could not find embedding for property ${firstPropertyBaseUrl} – skipping`, - ); + logger.error(`Could not find embedding for property ${firstPropertyBaseUrl} – skipping`); } } @@ -207,16 +185,12 @@ export const findExistingEntity = async ({ includeDrafts, includePermissions: false, }, - ).then(({ entities }) => - entities.slice(0, 3).map((entity) => new HashEntity(entity)), - ); + ).then(({ entities }) => entities.slice(0, 3).map((entity) => new HashEntity(entity))); } if (!potentialMatches?.length) { // If we didn't find a match on individual properties, try matching on the entire properties object - const propertyObjectEmbedding = embeddings.find( - (embedding) => !embedding.property, - ); + const propertyObjectEmbedding = embeddings.find((embedding) => !embedding.property); if (!propertyObjectEmbedding) { logger.error(`Could not find embedding for properties object – skipping`); @@ -243,9 +217,7 @@ export const findExistingEntity = async ({ includeDrafts, includePermissions: false, }, - ).then(({ entities }) => - entities.slice(0, 3).map((entity) => new HashEntity(entity)), - ); + ).then(({ entities }) => entities.slice(0, 3).map((entity) => new HashEntity(entity))); } } @@ -295,10 +267,7 @@ export const findExistingLinkEntity = async ({ { equal: [{ path: ["archived"] }, { parameter: false }] }, { any: proposedEntity.entityTypeIds.map((entityTypeId) => ({ - equal: [ - { path: ["type", "versionedUrl"] }, - { parameter: entityTypeId }, - ], + equal: [{ path: ["type", "versionedUrl"] }, { parameter: entityTypeId }], })), }, { @@ -345,9 +314,7 @@ export const findExistingLinkEntity = async ({ path: ["rightEntity", "uuid"], }, { - parameter: extractEntityUuidFromEntityId( - linkData.rightEntityId, - ), + parameter: extractEntityUuidFromEntityId(linkData.rightEntityId), }, ], }, @@ -363,8 +330,7 @@ export const findExistingLinkEntity = async ({ return null; } - const newInputHasNoProperties = - Object.keys(proposedEntity.properties).length === 0; + const newInputHasNoProperties = Object.keys(proposedEntity.properties).length === 0; if (newInputHasNoProperties) { const newInputTypeSet = new Set(proposedEntity.entityTypeIds); @@ -374,20 +340,18 @@ export const findExistingLinkEntity = async ({ * If we find it, we will take it as a match, on the basis that the only meaningful information present (types) matches. * We'll merge the sources listed for the edition to capture the fact that we inferred this link from multiple sources. */ - const potentialMatchWithNoProperties = linksWithOverlappingTypes.find( - (entity) => { - if (Object.keys(entity.properties).length !== 0) { - return false; - } - - const potentialMatchTypeSet = new Set(entity.metadata.entityTypeIds); - - return ( - newInputTypeSet.size === potentialMatchTypeSet.size && - newInputTypeSet.isSupersetOf(potentialMatchTypeSet) - ); - }, - ); + const potentialMatchWithNoProperties = linksWithOverlappingTypes.find((entity) => { + if (Object.keys(entity.properties).length !== 0) { + return false; + } + + const potentialMatchTypeSet = new Set(entity.metadata.entityTypeIds); + + return ( + newInputTypeSet.size === potentialMatchTypeSet.size && + newInputTypeSet.isSupersetOf(potentialMatchTypeSet) + ); + }); if (potentialMatchWithNoProperties) { return { @@ -397,8 +361,7 @@ export const findExistingLinkEntity = async ({ propertyMetadata: proposedEntity.propertyMetadata, editionSources: deduplicateSources([ ...(proposedEntity.provenance.sources ?? []), - ...(potentialMatchWithNoProperties.metadata.provenance.edition - .sources ?? []), + ...(potentialMatchWithNoProperties.metadata.provenance.edition.sources ?? []), ]), properties: {}, }, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-flow-context.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-flow-context.ts index 51012404cba..75d033b8642 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-flow-context.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-flow-context.ts @@ -45,9 +45,7 @@ export const getTemporalClient = async () => { * Get AI-specific workflow params from Temporal workflow history. * Extends the base workflow params with createEntitiesAsDraft and dataSources. */ -const getAiWorkflowParams = async (params: { - workflowId: string; -}): Promise => { +const getAiWorkflowParams = async (params: { workflowId: string }): Promise => { const { workflowId } = params; const cache = await getFlowContextCache(); @@ -77,9 +75,7 @@ const getAiWorkflowParams = async (params: { ); } - const inputs = parseHistoryItemPayload( - workflowExecutionStartedEventAttributes.input, - ); + const inputs = parseHistoryItemPayload(workflowExecutionStartedEventAttributes.input); if (!inputs) { throw new Error( @@ -90,20 +86,17 @@ const getAiWorkflowParams = async (params: { const [runFlowWorkflowParams] = inputs as RunAiFlowWorkflowParams[]; if (!runFlowWorkflowParams) { - throw new Error( - `No parameters of the "runFlow" workflow found for workflowId ${workflowId}`, - ); + throw new Error(`No parameters of the "runFlow" workflow found for workflowId ${workflowId}`); } - const draftTriggerInputNames: ( - | GoalFlowTriggerInput - | ManualInferenceTriggerInputName - )[] = ["Create as draft", "draft"]; + const draftTriggerInputNames: (GoalFlowTriggerInput | ManualInferenceTriggerInputName)[] = [ + "Create as draft", + "draft", + ]; - const createEntitiesAsDraft = - !!runFlowWorkflowParams.flowTrigger.outputs?.find((output) => - draftTriggerInputNames.includes(output.outputName as "draft"), - )?.payload.value; + const createEntitiesAsDraft = !!runFlowWorkflowParams.flowTrigger.outputs?.find((output) => + draftTriggerInputNames.includes(output.outputName as "draft"), + )?.payload.value; const aiParams: AiWorkflowParams = { createEntitiesAsDraft, @@ -201,10 +194,7 @@ export const getProvidedFiles = async (): Promise[]> => { ], }, { - equal: [ - { path: ["webId"] }, - { parameter: extractWebIdFromEntityId(fileEntityId) }, - ], + equal: [{ path: ["webId"] }, { parameter: extractWebIdFromEntityId(fileEntityId) }], }, { equal: [{ path: ["archived"] }, { parameter: false }] }, ], @@ -228,16 +218,11 @@ export const getProvidedFiles = async (): Promise[]> => { * - a URL from the database with spaces escaped (%20) may be played back with spaces * - a URL in the database may contain whitespace characters (e.g. NBSP / U+00A0 / 160) which are played back differently (U+0020 / 32) */ -export const areUrlsTheSameAfterNormalization = ( - first: string, - second: string, -) => +export const areUrlsTheSameAfterNormalization = (first: string, second: string) => decodeURIComponent(normalizeWhitespace(first)) === decodeURIComponent(normalizeWhitespace(second)); -export const getProvidedFileByUrl = async ( - url: string, -): Promise | undefined> => { +export const getProvidedFileByUrl = async (url: string): Promise | undefined> => { const files = await getProvidedFiles(); return files.find((file) => { /** @@ -245,9 +230,7 @@ export const getProvidedFileByUrl = async ( */ return areUrlsTheSameAfterNormalization( url, - file.properties[ - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/" - ], + file.properties["https://blockprotocol.org/@blockprotocol/types/property-type/file-url/"], ); }); }; @@ -260,5 +243,4 @@ export const getProvidedFileByUrl = async ( * * @see https://docs.temporal.io/activities#cancellation */ -export const isActivityCancelled = () => - Context.current().cancellationSignal.aborted; +export const isActivityCancelled = () => Context.current().cancellationSignal.aborted; diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response.ts index 425471821c3..23dde07a718 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response.ts @@ -16,11 +16,7 @@ import { isLlmParamsGoogleAiParams, } from "./get-llm-response/types.js"; -import type { - LlmParams, - LlmRequestMetadata, - LlmResponse, -} from "./get-llm-response/types.js"; +import type { LlmParams, LlmRequestMetadata, LlmResponse } from "./get-llm-response/types.js"; import type { EntityId, UserId, WebId } from "@blockprotocol/type-system"; import type { GraphApi } from "@local/hash-graph-client"; import type { FlowUsageRecordCustomMetadata } from "@local/hash-isomorphic-utils/flows/types"; @@ -47,8 +43,7 @@ export const getLlmResponse = async ( llmParams: T, usageTrackingParams: UsageTrackingParams, ): Promise> => { - const { customMetadata, graphApiClient, userAccountId, webId } = - usageTrackingParams; + const { customMetadata, graphApiClient, userAccountId, webId } = usageTrackingParams; /** * Check whether the web has exceeded its usage limit, before proceeding with the LLM request. @@ -114,9 +109,7 @@ export const getLlmResponse = async ( stepId, }; - const { llmResponse, transformedRequest } = isLlmParamsAnthropicLlmParams( - llmParams, - ) + const { llmResponse, transformedRequest } = isLlmParamsAnthropicLlmParams(llmParams) ? await getAnthropicResponse(llmParams, metadata) : isLlmParamsGoogleAiParams(llmParams) ? await getGoogleAiResponse(llmParams, metadata) diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/anthropic-client.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/anthropic-client.ts index 7a5b6fc13e8..29380758486 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/anthropic-client.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/anthropic-client.ts @@ -25,26 +25,18 @@ const permittedAnthropicModels = [ export type PermittedAnthropicModel = (typeof permittedAnthropicModels)[number]; -export const isPermittedAnthropicModel = ( - model: string, -): model is PermittedAnthropicModel => +export const isPermittedAnthropicModel = (model: string): model is PermittedAnthropicModel => permittedAnthropicModels.includes(model as PermittedAnthropicModel); /** @see https://docs.anthropic.com/claude/docs/models-overview#model-comparison */ -export const anthropicMessageModelToContextWindow: Record< - PermittedAnthropicModel, - number -> = { +export const anthropicMessageModelToContextWindow: Record = { "claude-haiku-4-5-20251001": 200_000, "claude-opus-4-6": 200_000, "claude-sonnet-4-6": 200_000, }; /** @see https://docs.anthropic.com/en/docs/about-claude/models#model-comparison */ -export const anthropicMessageModelToMaxOutput: Record< - PermittedAnthropicModel, - number -> = { +export const anthropicMessageModelToMaxOutput: Record = { // actually 64k, but we should implement streaming mode to handle higher. "claude-haiku-4-5-20251001": 12_000, // actually 128k, but we should implement streaming mode to handle higher. @@ -67,12 +59,8 @@ export type AnthropicMessagesCreateResponse = Message & { provider: AnthropicApiProvider; }; -const awsAccessKey = getRequiredEnv( - "HASH_TEMPORAL_WORKER_AI_AWS_ACCESS_KEY_ID", -); -const awsSecretKey = getRequiredEnv( - "HASH_TEMPORAL_WORKER_AI_AWS_SECRET_ACCESS_KEY", -); +const awsAccessKey = getRequiredEnv("HASH_TEMPORAL_WORKER_AI_AWS_ACCESS_KEY_ID"); +const awsSecretKey = getRequiredEnv("HASH_TEMPORAL_WORKER_AI_AWS_SECRET_ACCESS_KEY"); /** * Currently this is the only region supporting Claude 3 Opus. */ @@ -90,14 +78,12 @@ type AnthropicBedrockModel = | "anthropic.claude-sonnet-4-6"; /** @see https://docs.anthropic.com/en/api/claude-on-amazon-bedrock#api-model-names */ -export const anthropicModelToBedrockModel: Record< - PermittedAnthropicModel, - AnthropicBedrockModel -> = { - "claude-haiku-4-5-20251001": "anthropic.claude-haiku-4-5-20251001-v1:0", - "claude-opus-4-6": "anthropic.claude-opus-4-6-v1", - "claude-sonnet-4-6": "anthropic.claude-sonnet-4-6", -}; +export const anthropicModelToBedrockModel: Record = + { + "claude-haiku-4-5-20251001": "anthropic.claude-haiku-4-5-20251001-v1:0", + "claude-opus-4-6": "anthropic.claude-opus-4-6-v1", + "claude-sonnet-4-6": "anthropic.claude-sonnet-4-6", + }; export type AnthropicApiProvider = "anthropic" | "amazon-bedrock"; diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/check-web-service-usage-not-exceeded.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/check-web-service-usage-not-exceeded.ts index 3f3c74625f4..fd981a098f0 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/check-web-service-usage-not-exceeded.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/check-web-service-usage-not-exceeded.ts @@ -35,9 +35,7 @@ export const checkWebServiceUsageNotExceeded = async (params: { decisionTimeInterval: { start: { kind: "inclusive", - limit: generateTimestamp( - new Date(now.valueOf() - 1000 * 60 * 60 * 24 * 30), - ), + limit: generateTimestamp(new Date(now.valueOf() - 1000 * 60 * 60 * 24 * 30)), }, end: { kind: "inclusive", @@ -64,12 +62,9 @@ export const checkWebServiceUsageNotExceeded = async (params: { { userAccountId: userAuthenticationInfo.actorId }, ); - const { day: dayLimit, month: monthLimit } = - usageCostLimit[isUserAdmin ? "admin" : "web"]; + const { day: dayLimit, month: monthLimit } = usageCostLimit[isUserAdmin ? "admin" : "web"]; - const errorPrefix = isUserAdmin - ? "You have exceeded your admin" - : "The web has exceeded its"; + const errorPrefix = isUserAdmin ? "You have exceeded your admin" : "The web has exceeded its"; if (lastDaysCost >= dayLimit) { return { diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-anthropic-response.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-anthropic-response.ts index 68981853c0f..9054942bbde 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-anthropic-response.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-anthropic-response.ts @@ -16,25 +16,16 @@ import { maxRetryCount, serverErrorRetryStartingDelay, } from "./constants.js"; -import { - mapAnthropicMessageToLlmMessage, - mapLlmMessageToAnthropicMessage, -} from "./llm-message.js"; +import { mapAnthropicMessageToLlmMessage, mapLlmMessageToAnthropicMessage } from "./llm-message.js"; import { logLlmRequest, logLlmServerError } from "./log-llm-request.js"; -import { - getInputValidationErrors, - sanitizeInputBeforeValidation, -} from "./validation.js"; +import { getInputValidationErrors, sanitizeInputBeforeValidation } from "./validation.js"; import type { AnthropicApiProvider, AnthropicMessagesCreateParams, AnthropicMessagesCreateResponse, } from "./anthropic-client.js"; -import type { - LlmMessageToolUseContent, - LlmUserMessage, -} from "./llm-message.js"; +import type { LlmMessageToolUseContent, LlmUserMessage } from "./llm-message.js"; import type { AnthropicLlmParams, AnthropicResponse, @@ -48,9 +39,7 @@ import type { import type { APIError, RateLimitError } from "@anthropic-ai/sdk/error"; import type { Tool } from "@anthropic-ai/sdk/resources/messages"; -const mapLlmToolDefinitionToAnthropicToolDefinition = ( - tool: LlmToolDefinition, -): Tool => ({ +const mapLlmToolDefinitionToAnthropicToolDefinition = (tool: LlmToolDefinition): Tool => ({ name: tool.name, description: tool.description, input_schema: tool.inputSchema, @@ -120,13 +109,8 @@ const getWaitPeriodFromHeaders = (headers?: Headers): number => { return Math.max(tokenReset ?? 0, requestReset ?? 0); }; -const isErrorAnthropicRateLimitingError = ( - error: unknown, -): error is RateLimitError => - typeof error === "object" && - !!error && - "status" in error && - error.status === 429; +const isErrorAnthropicRateLimitingError = (error: unknown): error is RateLimitError => + typeof error === "object" && !!error && "status" in error && error.status === 429; const isServerError = (error: unknown): error is APIError => typeof error === "object" && @@ -146,13 +130,7 @@ const createAnthropicMessagesWithToolsWithBackoff = async (params: { retryCount?: number; priorRateLimitError?: Partial>; }): Promise => { - const { - metadata, - payload, - retryCount = 1, - initialProvider, - priorRateLimitError, - } = params; + const { metadata, payload, retryCount = 1, initialProvider, priorRateLimitError } = params; let currentProvider: AnthropicApiProvider = initialProvider; @@ -188,8 +166,7 @@ const createAnthropicMessagesWithToolsWithBackoff = async (params: { */ if (isServerError(error)) { const otherProvider = switchProvider(currentProvider); - const priorRateLimitErrorForOtherProvider = - priorRateLimitError?.[otherProvider]; + const priorRateLimitErrorForOtherProvider = priorRateLimitError?.[otherProvider]; /** * We only retry the request with the other provider if we didn't previously @@ -199,9 +176,7 @@ const createAnthropicMessagesWithToolsWithBackoff = async (params: { */ logger.debug( `Encountered server error with provider "${currentProvider}" for request ${metadata.requestId}, retrying with exponential backoff with provider "${ - priorRateLimitErrorForOtherProvider - ? currentProvider - : otherProvider + priorRateLimitErrorForOtherProvider ? currentProvider : otherProvider }".`, ); if (!priorRateLimitErrorForOtherProvider) { @@ -246,8 +221,7 @@ const createAnthropicMessagesWithToolsWithBackoff = async (params: { }); } - const otherProviderPriorRateLimitError = - priorRateLimitError[otherProvider]; + const otherProviderPriorRateLimitError = priorRateLimitError[otherProvider]; if (otherProviderPriorRateLimitError) { /** @@ -255,9 +229,7 @@ const createAnthropicMessagesWithToolsWithBackoff = async (params: { * we need to wait for the smaller of the two starting delays * before retrying the request with the corresponding provider. */ - const currentProviderStartingDelay = getWaitPeriodFromHeaders( - currentProviderError.headers, - ); + const currentProviderStartingDelay = getWaitPeriodFromHeaders(currentProviderError.headers); const otherProviderStartingDelay = getWaitPeriodFromHeaders( otherProviderPriorRateLimitError.headers, @@ -317,19 +289,14 @@ export const getAnthropicResponse = async ( ...remainingParams } = params; - const anthropicTools = tools?.map( - mapLlmToolDefinitionToAnthropicToolDefinition, - ); + const anthropicTools = tools?.map(mapLlmToolDefinitionToAnthropicToolDefinition); - const anthropicMessages = messages.map((message) => - mapLlmMessageToAnthropicMessage({ message }), - ); + const anthropicMessages = messages.map((message) => mapLlmMessageToAnthropicMessage({ message })); /** * Default to the maximum context window, if `max_tokens` is not provided. */ - const maxTokens = - params.maxTokens ?? anthropicMessageModelToMaxOutput[params.model]; + const maxTokens = params.maxTokens ?? anthropicMessageModelToMaxOutput[params.model]; let anthropicResponse: AnthropicMessagesCreateResponse; @@ -371,10 +338,7 @@ export const getAnthropicResponse = async ( }; } - const message = - "message" in (error as Error) - ? (error as Error).message - : "Unknown error"; + const message = "message" in (error as Error) ? (error as Error).message : "Unknown error"; return { llmResponse: { @@ -389,11 +353,8 @@ export const getAnthropicResponse = async ( const { previousUsage, retryCount = 0 } = retryContext ?? {}; const usage: LlmUsage = { - inputTokens: - (previousUsage?.inputTokens ?? 0) + anthropicResponse.usage.input_tokens, - outputTokens: - (previousUsage?.outputTokens ?? 0) + - anthropicResponse.usage.output_tokens, + inputTokens: (previousUsage?.inputTokens ?? 0) + anthropicResponse.usage.input_tokens, + outputTokens: (previousUsage?.outputTokens ?? 0) + anthropicResponse.usage.output_tokens, totalTokens: (previousUsage?.totalTokens ?? 0) + anthropicResponse.usage.input_tokens + @@ -423,9 +384,7 @@ export const getAnthropicResponse = async ( }; } - const stopReason = mapAnthropicStopReasonToLlmStopReason( - anthropicResponse.stop_reason, - ); + const stopReason = mapAnthropicStopReasonToLlmStopReason(anthropicResponse.stop_reason); const retry = async (retryParams: { successfullyParsedToolCalls: ParsedLlmToolCall[]; @@ -459,8 +418,7 @@ export const getAnthropicResponse = async ( !( messageContent.type === "tool_use" && retryParams.successfullyParsedToolCalls.some( - (successFullToolCall) => - successFullToolCall.id === messageContent.id, + (successFullToolCall) => successFullToolCall.id === messageContent.id, ) ), ), @@ -523,8 +481,7 @@ export const getAnthropicResponse = async ( const parsedToolCalls: ParsedLlmToolCall[] = []; - const unvalidatedParsedToolCalls = - parseToolCallsFromAnthropicResponse(anthropicResponse); + const unvalidatedParsedToolCalls = parseToolCallsFromAnthropicResponse(anthropicResponse); if (stopReason === "tool_use" && unvalidatedParsedToolCalls.length > 0) { const retryMessageContent: LlmUserMessage["content"] = []; @@ -597,10 +554,9 @@ export const getAnthropicResponse = async ( * response message, which may have been previously filtered out. */ if (retryContext) { - const previousSuccessfulToolUses = - retryContext.previousSuccessfulToolCalls.map< - LlmMessageToolUseContent - >(({ id, input, name }) => ({ type: "tool_use", id, input, name })); + const previousSuccessfulToolUses = retryContext.previousSuccessfulToolCalls.map< + LlmMessageToolUseContent + >(({ id, input, name }) => ({ type: "tool_use", id, input, name })); message.content.push(...previousSuccessfulToolUses); } diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response.ts index b89cf673335..c6dfabb54ad 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response.ts @@ -90,18 +90,14 @@ export const getGoogleAiResponse = async ( function_calling_config: { mode: FunctionCallingMode.ANY, allowed_function_names: - toolChoice !== "required" - ? [toolChoice] - : tools.map((tool) => tool.name), + toolChoice !== "required" ? [toolChoice] : tools.map((tool) => tool.name), }, } : undefined, tools: tools ? [ { - functionDeclarations: tools.map( - mapLlmToolDefinitionToGoogleAiToolDefinition, - ), + functionDeclarations: tools.map(mapLlmToolDefinitionToGoogleAiToolDefinition), }, ] : undefined, @@ -122,10 +118,7 @@ export const getGoogleAiResponse = async ( }; } - const message = - "message" in (error as Error) - ? (error as Error).message - : "Unknown error"; + const message = "message" in (error as Error) ? (error as Error).message : "Unknown error"; return { llmResponse: { @@ -186,14 +179,9 @@ export const getGoogleAiResponse = async ( } const usage: LlmUsage = { - inputTokens: - (previousUsage?.inputTokens ?? 0) + - (usageMetadata?.promptTokenCount ?? 0), - outputTokens: - (previousUsage?.outputTokens ?? 0) + - (usageMetadata?.candidatesTokenCount ?? 0), - totalTokens: - (previousUsage?.totalTokens ?? 0) + (usageMetadata?.totalTokenCount ?? 0), + inputTokens: (previousUsage?.inputTokens ?? 0) + (usageMetadata?.promptTokenCount ?? 0), + outputTokens: (previousUsage?.outputTokens ?? 0) + (usageMetadata?.candidatesTokenCount ?? 0), + totalTokens: (previousUsage?.totalTokens ?? 0) + (usageMetadata?.totalTokenCount ?? 0), }; const normalizedResponse: LlmResponse = { diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/google-cloud-storage.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/google-cloud-storage.ts index a75e4ad5c1a..12fe557a4bb 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/google-cloud-storage.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/google-cloud-storage.ts @@ -26,9 +26,7 @@ export const generateStoragePathFromHashFileStorageKey = ({ hashFileStorageKey: string; }): string => { if (!storageBucket) { - throw new Error( - "GOOGLE_CLOUD_STORAGE_BUCKET environment variable is not set", - ); + throw new Error("GOOGLE_CLOUD_STORAGE_BUCKET environment variable is not set"); } return `gs://${storageBucket}/${hashFileStorageKey}`; @@ -42,9 +40,7 @@ const getHashFileStorageKeyFromGcpStorageUri = ({ const hashFileStorageKey = gcpStorageUri.split("/").pop(); if (!hashFileStorageKey) { - throw new Error( - `Hash file storage key not found in storage path ${gcpStorageUri}`, - ); + throw new Error(`Hash file storage key not found in storage path ${gcpStorageUri}`); } return hashFileStorageKey; @@ -63,15 +59,12 @@ export const getFileEntityFromGcpStorageUri = ({ const fileEntity = fileEntities.find( (entity) => - entity.properties[ - "https://hash.ai/@h/types/property-type/file-storage-key/" - ] === hashFileStorageKey, + entity.properties["https://hash.ai/@h/types/property-type/file-storage-key/"] === + hashFileStorageKey, ); if (!fileEntity) { - throw new Error( - `File entity not found for storage key ${hashFileStorageKey}`, - ); + throw new Error(`File entity not found for storage key ${hashFileStorageKey}`); } return fileEntity; @@ -87,20 +80,14 @@ export const uploadFileToGcpStorage = async ({ const storage = getGoogleCloudStorage(); if (!storageBucket) { - throw new Error( - "GOOGLE_CLOUD_STORAGE_BUCKET environment variable is not set", - ); + throw new Error("GOOGLE_CLOUD_STORAGE_BUCKET environment variable is not set"); } const hashFileStorageKey = - fileEntity.properties[ - "https://hash.ai/@h/types/property-type/file-storage-key/" - ]; + fileEntity.properties["https://hash.ai/@h/types/property-type/file-storage-key/"]; if (!hashFileStorageKey) { - throw new Error( - `File entity ${fileEntity.entityId} has no file storage key`, - ); + throw new Error(`File entity ${fileEntity.entityId} has no file storage key`); } const cloudStorageFilePath = generateStoragePathFromHashFileStorageKey({ diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-google-messages-to-llm-messages.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-google-messages-to-llm-messages.ts index a0da9b41a6c..15bfcb08c79 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-google-messages-to-llm-messages.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-google-messages-to-llm-messages.ts @@ -59,9 +59,7 @@ export const mapGoogleMessagesToLlmMessages = (params: { }; } - throw new Error( - `Unexpected content type for 'user' message: ${JSON.stringify(part)}`, - ); + throw new Error(`Unexpected content type for 'user' message: ${JSON.stringify(part)}`); }), }; } else if (message.role === "model") { diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-parts-and-upload-files.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-parts-and-upload-files.ts index 81c0b89df71..183777bce57 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-parts-and-upload-files.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/map-parts-and-upload-files.ts @@ -18,35 +18,32 @@ export const mapLlmContentToGooglePartAndUploadFiles = async ( case "file": { const { fileEntity } = content; - return await useFileSystemPathFromEntity( - fileEntity, - async ({ fileSystemPath }) => { - const { gcpStorageUri } = await uploadFileToGcpStorage({ - fileEntity, - fileSystemPath, - }); + return await useFileSystemPathFromEntity(fileEntity, async ({ fileSystemPath }) => { + const { gcpStorageUri } = await uploadFileToGcpStorage({ + fileEntity, + fileSystemPath, + }); - const mimeType = - fileEntity.properties[ - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/" - ]; + const mimeType = + fileEntity.properties[ + "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/" + ]; - if (!mimeType) { - throw new Error( - `File entity with entityId ${fileEntity.entityId} does not have a mimeType property`, - ); - } + if (!mimeType) { + throw new Error( + `File entity with entityId ${fileEntity.entityId} does not have a mimeType property`, + ); + } - const uploadedFileData = { - fileData: { - fileUri: gcpStorageUri, - mimeType, - }, - } satisfies FileDataPart; + const uploadedFileData = { + fileData: { + fileUri: gcpStorageUri, + mimeType, + }, + } satisfies FileDataPart; - return uploadedFileData; - }, - ); + return uploadedFileData; + }); } case "text": { return { @@ -68,9 +65,7 @@ export const mapLlmContentToGooglePartAndUploadFiles = async ( }, } satisfies FunctionResponsePart; } catch { - throw new Error( - `Failed to parse tool result content: ${content.content}`, - ); + throw new Error(`Failed to parse tool result content: ${content.content}`); } } case "tool_use": { diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/rewrite-schema-for-google.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/rewrite-schema-for-google.ts index 58bceff0073..7379222abb4 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/rewrite-schema-for-google.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-google-ai-response/rewrite-schema-for-google.ts @@ -39,18 +39,9 @@ const vertexSchemaUnsupportedFields = ["$id", "multipleOf", "pattern"] as const; * These are special fields we use in HASH but do not appear in any JSON Schema spec. * They will never be supported in Vertex AI, so we must remove them. */ -const nonStandardSchemaFields = [ - "abstract", - "titlePlural", - "kind", - "labelProperty", - "inverse", -]; - -const fieldsToExclude = [ - ...vertexSchemaUnsupportedFields, - ...nonStandardSchemaFields, -]; +const nonStandardSchemaFields = ["abstract", "titlePlural", "kind", "labelProperty", "inverse"]; + +const fieldsToExclude = [...vertexSchemaUnsupportedFields, ...nonStandardSchemaFields]; /** * @see https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/control-generated-output#fields @@ -65,9 +56,7 @@ function assertNonBoolean(value: T): asserts value is Exclude { } } -export const rewriteSchemaPart = ( - schema: SchemaValue | SchemaValue[], -): SchemaValue => { +export const rewriteSchemaPart = (schema: SchemaValue | SchemaValue[]): SchemaValue => { if (typeof schema !== "object" || schema === null) { return schema; } @@ -81,9 +70,7 @@ export const rewriteSchemaPart = ( const result: Schema = {}; - for (const [uncheckedKey, value] of Object.entries( - schema as Record, - )) { + for (const [uncheckedKey, value] of Object.entries(schema as Record)) { const key = uncheckedKey === "oneOf" ? "anyOf" : uncheckedKey; if (key === "format" && typeof value === "string") { @@ -164,13 +151,10 @@ export const rewriteSchemaPart = ( * * If we define a type it will incorrect be constrainted to '{type} | null'. */ - throw new Error( - "Property type must have at least one option which is not null", - ); + throw new Error("Property type must have at least one option which is not null"); } - (value.oneOf as NonNullable) = - mustHaveAtLeastOne(newOneOf); + (value.oneOf as NonNullable) = mustHaveAtLeastOne(newOneOf); } // @ts-expect-error -- @todo fix this diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-openai-reponse.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-openai-reponse.ts index 0ed07a37879..33e3b9013e5 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-openai-reponse.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/get-openai-reponse.ts @@ -15,15 +15,9 @@ import { maxRetryCount, serverErrorRetryStartingDelay, } from "./constants.js"; -import { - mapLlmMessageToOpenAiMessages, - mapOpenAiMessagesToLlmMessages, -} from "./llm-message.js"; +import { mapLlmMessageToOpenAiMessages, mapOpenAiMessagesToLlmMessages } from "./llm-message.js"; import { logLlmRequest, logLlmServerError } from "./log-llm-request.js"; -import { - getInputValidationErrors, - sanitizeInputBeforeValidation, -} from "./validation.js"; +import { getInputValidationErrors, sanitizeInputBeforeValidation } from "./validation.js"; import type { LlmAssistantMessage, @@ -122,10 +116,7 @@ const getWaitPeriodFromHeaders = (headers?: Headers): number => { }; const isServerError = (error: unknown): error is APIError => - error instanceof APIError && - !!error.status && - error.status >= 500 && - error.status < 600; + error instanceof APIError && !!error.status && error.status >= 500 && error.status < 600; const openAiChatCompletionWithBackoff = async (params: { completionPayload: OpenAI.ChatCompletionCreateParamsNonStreaming; @@ -175,10 +166,7 @@ const openAiChatCompletionWithBackoff = async (params: { }, ); } catch (error) { - if ( - error instanceof RateLimitError && - retryCount < maximumRateLimitRetries - ) { + if (error instanceof RateLimitError && retryCount < maximumRateLimitRetries) { logger.debug( `Encountered rate limit error with OpenAI provider, delaying retry request until the rate limit wait period has ended.`, ); @@ -230,9 +218,7 @@ export const getOpenAiResponse = async ( }, ] : []), - ...messages.flatMap((message) => - mapLlmMessageToOpenAiMessages({ message }), - ), + ...messages.flatMap((message) => mapLlmMessageToOpenAiMessages({ message })), ]; const completionPayload: OpenAI.ChatCompletionCreateParamsNonStreaming = { @@ -244,8 +230,7 @@ export const getOpenAiResponse = async ( * Return `logprobs` by default when in development mode, unless * explicitly overridden by the caller. */ - logprobs: - remainingParams.logprobs ?? process.env.NODE_ENV === "development", + logprobs: remainingParams.logprobs ?? process.env.NODE_ENV === "development", tool_choice: toolChoice ? toolChoice === "required" ? "required" @@ -275,8 +260,7 @@ export const getOpenAiResponse = async ( logger.info(`Estimated prompt tokens: ${estimatedPromptTokens}`); - excessTokens = - estimatedPromptTokens + completionPayloadOverhead - modelContextWindow; + excessTokens = estimatedPromptTokens + completionPayloadOverhead - modelContextWindow; if (excessTokens < 10) { break; @@ -288,14 +272,10 @@ export const getOpenAiResponse = async ( } characters.`, ); - const firstUserMessageContent = - completionPayload.messages[trimMessageAtIndex]!.content; + const firstUserMessageContent = completionPayload.messages[trimMessageAtIndex]!.content; completionPayload.messages[trimMessageAtIndex]!.content = - firstUserMessageContent?.slice( - 0, - firstUserMessageContent.length - excessTokens * 4, - ) ?? ""; + firstUserMessageContent?.slice(0, firstUserMessageContent.length - excessTokens * 4) ?? ""; } while (excessTokens > 9); } @@ -320,10 +300,7 @@ export const getOpenAiResponse = async ( }; } - const message = - "message" in (error as Error) - ? (error as Error).message - : "Unknown error"; + const message = "message" in (error as Error) ? (error as Error).message : "Unknown error"; return { llmResponse: { @@ -340,15 +317,10 @@ export const getOpenAiResponse = async ( const { previousUsage, retryCount = 0 } = retryContext ?? {}; const usage: LlmUsage = { - inputTokens: - (previousUsage?.inputTokens ?? 0) + - (openAiResponse.usage?.prompt_tokens ?? 0), + inputTokens: (previousUsage?.inputTokens ?? 0) + (openAiResponse.usage?.prompt_tokens ?? 0), outputTokens: - (previousUsage?.outputTokens ?? 0) + - (openAiResponse.usage?.completion_tokens ?? 0), - totalTokens: - (previousUsage?.totalTokens ?? 0) + - (openAiResponse.usage?.total_tokens ?? 0), + (previousUsage?.outputTokens ?? 0) + (openAiResponse.usage?.completion_tokens ?? 0), + totalTokens: (previousUsage?.totalTokens ?? 0) + (openAiResponse.usage?.total_tokens ?? 0), }; const lastRequestTime = currentRequestTime; @@ -577,10 +549,7 @@ export const getOpenAiResponse = async ( }); } - if ( - firstChoice.finish_reason === "tool_calls" && - parsedToolCalls.length === 0 - ) { + if (firstChoice.finish_reason === "tool_calls" && parsedToolCalls.length === 0) { return retry({ successfullyParsedToolCalls: [], retryMessageContent: [ @@ -595,18 +564,13 @@ export const getOpenAiResponse = async ( if (!openAiResponse.usage) { logger.error(`OpenAI returned no usage information for call`); } else { - const { completion_tokens, prompt_tokens, total_tokens } = - openAiResponse.usage; + const { completion_tokens, prompt_tokens, total_tokens } = openAiResponse.usage; logger.info( `Actual usage for iteration: prompt tokens: ${prompt_tokens}, completion tokens: ${completion_tokens}, total tokens: ${total_tokens}`, ); if (estimatedPromptTokens) { - logger.info( - `Estimated prompt usage off by ${ - prompt_tokens - estimatedPromptTokens - } tokens.`, - ); + logger.info(`Estimated prompt usage off by ${prompt_tokens - estimatedPromptTokens} tokens.`); } } @@ -634,10 +598,9 @@ export const getOpenAiResponse = async ( * response message, which may have been previously filtered out. */ if (retryContext) { - const previousSuccessfulToolUses = - retryContext.previousSuccessfulToolCalls.map< - LlmMessageToolUseContent - >(({ id, input, name }) => ({ type: "tool_use", id, input, name })); + const previousSuccessfulToolUses = retryContext.previousSuccessfulToolCalls.map< + LlmMessageToolUseContent + >(({ id, input, name }) => ({ type: "tool_use", id, input, name })); responseMessage.content.push(...previousSuccessfulToolUses); } diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/google-vertex-ai-client.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/google-vertex-ai-client.ts index 1aebeab08e9..1ecde6c8681 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/google-vertex-ai-client.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/google-vertex-ai-client.ts @@ -2,30 +2,20 @@ import { VertexAI } from "@google-cloud/vertexai"; import type { MessageCreateParamsBase } from "@anthropic-ai/sdk/resources/messages.mjs"; -const permittedGoogleAiModels = [ - "gemini-1.5-pro-002", -] satisfies MessageCreateParamsBase["model"][]; +const permittedGoogleAiModels = ["gemini-1.5-pro-002"] satisfies MessageCreateParamsBase["model"][]; export type PermittedGoogleAiModel = (typeof permittedGoogleAiModels)[number]; -export const isPermittedGoogleAiModel = ( - model: string, -): model is PermittedGoogleAiModel => +export const isPermittedGoogleAiModel = (model: string): model is PermittedGoogleAiModel => permittedGoogleAiModels.includes(model as PermittedGoogleAiModel); /** @see https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models */ -export const googleAiMessageModelToContextWindow: Record< - PermittedGoogleAiModel, - number -> = { +export const googleAiMessageModelToContextWindow: Record = { "gemini-1.5-pro-002": 2_097_152, }; /** @see https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models */ -export const googleAiMessageModelToMaxOutput: Record< - PermittedGoogleAiModel, - number -> = { +export const googleAiMessageModelToMaxOutput: Record = { "gemini-1.5-pro-002": 8_192, }; const googleCloudProjectId = process.env.GOOGLE_CLOUD_HASH_PROJECT_ID; @@ -34,9 +24,7 @@ let _vertexAi: VertexAI | undefined; export const getVertexAiClient = () => { if (!googleCloudProjectId) { - throw new Error( - "GOOGLE_CLOUD_HASH_PROJECT_ID environment variable is not set", - ); + throw new Error("GOOGLE_CLOUD_HASH_PROJECT_ID environment variable is not set"); } if (_vertexAi) { diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/llm-message.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/llm-message.ts index eb10cce24e8..7edcf8146ad 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/llm-message.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/llm-message.ts @@ -39,11 +39,7 @@ export type LlmMessageToolResultContent = { export type LlmUserMessage = { role: "user"; - content: ( - | LlmMessageTextContent - | LlmMessageToolResultContent - | LlmFileMessageContent - )[]; + content: (LlmMessageTextContent | LlmMessageToolResultContent | LlmFileMessageContent)[]; }; export type LlmMessage = LlmAssistantMessage | LlmUserMessage; @@ -93,9 +89,7 @@ export const mapAnthropicMessageToLlmMessage = (params: { throw new Error("Image content not supported"); } else if (content.type === "tool_result") { throw new Error( - `Anthropic assistant message contains a tool result: ${JSON.stringify( - content, - )}`, + `Anthropic assistant message contains a tool result: ${JSON.stringify(content)}`, ); } else if (content.type === "tool_use") { return { @@ -108,9 +102,7 @@ export const mapAnthropicMessageToLlmMessage = (params: { return content; } - throw new Error( - `Unexpected content type: ${JSON.stringify(content)}`, - ); + throw new Error(`Unexpected content type: ${JSON.stringify(content)}`); }), }; } @@ -149,9 +141,7 @@ export const mapAnthropicMessageToLlmMessage = (params: { return content; } - throw new Error( - `Unexpected content type in tool result: ${content.type}`, - ); + throw new Error(`Unexpected content type in tool result: ${content.type}`); }); return { @@ -165,21 +155,16 @@ export const mapAnthropicMessageToLlmMessage = (params: { return block; } - throw new Error( - `Unexpected content type: ${JSON.stringify(block)}`, - ); + throw new Error(`Unexpected content type: ${JSON.stringify(block)}`); }), }; }; -export const getToolCallsFromLlmAssistantMessage = < - ToolName extends string = string, ->(params: { +export const getToolCallsFromLlmAssistantMessage = (params: { message: LlmAssistantMessage; }): LlmMessageToolUseContent[] => params.message.content.filter( - (content): content is LlmMessageToolUseContent => - content.type === "tool_use", + (content): content is LlmMessageToolUseContent => content.type === "tool_use", ); export const getTextContentFromLlmMessage = (params: { @@ -255,129 +240,112 @@ export const mapOpenAiMessagesToLlmMessages = (params: { }): LlmMessage[] => { const { messages } = params; - return messages.reduce( - (previousLlmMessages, currentMessage) => { - if (currentMessage.role === "assistant") { - const toolCalls = - currentMessage.tool_calls?.map( - (toolCall) => { - const rawInput = - toolCall.type === "function" - ? toolCall.function.arguments - : toolCall.custom.input; - - const rawName = - toolCall.type === "function" - ? toolCall.function.name - : toolCall.custom.name; - - let jsonInput: object; - try { - jsonInput = JSON.parse(rawInput) as object; - } catch { - // model's input could not be parsed, this is likely a retry of a failed tool call - jsonInput = { unparseableInput: rawInput }; - } - - return { - type: "tool_use" as const, - id: toolCall.id, - name: sanitizeToolCallName(rawName), - input: jsonInput, - }; - }, - ); + return messages.reduce((previousLlmMessages, currentMessage) => { + if (currentMessage.role === "assistant") { + const toolCalls = currentMessage.tool_calls?.map((toolCall) => { + const rawInput = + toolCall.type === "function" ? toolCall.function.arguments : toolCall.custom.input; + + const rawName = + toolCall.type === "function" ? toolCall.function.name : toolCall.custom.name; + + let jsonInput: object; + try { + jsonInput = JSON.parse(rawInput) as object; + } catch { + // model's input could not be parsed, this is likely a retry of a failed tool call + jsonInput = { unparseableInput: rawInput }; + } - return [ - ...previousLlmMessages, - { - role: "assistant", - content: [ - ...(currentMessage.content && - typeof currentMessage.content === "string" - ? [ - { + return { + type: "tool_use" as const, + id: toolCall.id, + name: sanitizeToolCallName(rawName), + input: jsonInput, + }; + }); + + return [ + ...previousLlmMessages, + { + role: "assistant", + content: [ + ...(currentMessage.content && typeof currentMessage.content === "string" + ? [ + { + type: "text" as const, + text: currentMessage.content, + }, + ] + : []), + ...(toolCalls ?? []), + ], + } satisfies LlmAssistantMessage, + ]; + } else if (currentMessage.role === "user") { + return [ + ...previousLlmMessages, + { + role: "user", + content: currentMessage.content + ? typeof currentMessage.content === "string" + ? [ + { + type: "text" as const, + text: currentMessage.content, + }, + ] + : currentMessage.content.map((content) => { + if (content.type === "text") { + return { type: "text" as const, - text: currentMessage.content, - }, - ] - : []), - ...(toolCalls ?? []), - ], - } satisfies LlmAssistantMessage, - ]; - } else if (currentMessage.role === "user") { + text: content.text, + }; + } + throw new Error(`Unexpected content type: ${content.type}`); + }) + : [], + } satisfies LlmUserMessage, + ]; + } else if (currentMessage.role === "tool") { + const textualContent = + typeof currentMessage.content === "string" + ? currentMessage.content + : currentMessage.content.map((contentPart) => contentPart.text).join("\n"); + + const toolResultContent: LlmMessageToolResultContent = { + type: "tool_result", + tool_use_id: currentMessage.tool_call_id, + content: textualContent, + }; + + const previousLlmMessage = previousLlmMessages.slice(-1)[0]; + + if (!previousLlmMessage || previousLlmMessage.role !== "user") { + /** + * If there is no previous message, or the previous message + * is not a `user` message, then create a new `user` message + * with the tool result content. + */ return [ ...previousLlmMessages, { role: "user", - content: currentMessage.content - ? typeof currentMessage.content === "string" - ? [ - { - type: "text" as const, - text: currentMessage.content, - }, - ] - : currentMessage.content.map( - (content) => { - if (content.type === "text") { - return { - type: "text" as const, - text: content.text, - }; - } - throw new Error( - `Unexpected content type: ${content.type}`, - ); - }, - ) - : [], - } satisfies LlmUserMessage, + content: [toolResultContent], + } as LlmUserMessage, ]; - } else if (currentMessage.role === "tool") { - const textualContent = - typeof currentMessage.content === "string" - ? currentMessage.content - : currentMessage.content - .map((contentPart) => contentPart.text) - .join("\n"); - - const toolResultContent: LlmMessageToolResultContent = { - type: "tool_result", - tool_use_id: currentMessage.tool_call_id, - content: textualContent, - }; - - const previousLlmMessage = previousLlmMessages.slice(-1)[0]; - - if (!previousLlmMessage || previousLlmMessage.role !== "user") { - /** - * If there is no previous message, or the previous message - * is not a `user` message, then create a new `user` message - * with the tool result content. - */ - return [ - ...previousLlmMessages, - { - role: "user", - content: [toolResultContent], - } as LlmUserMessage, - ]; - } - - /** - * If the previous message is a `user` message, then append - * the tool result content to the previous message to avoid - * consecutive `user` messages. - */ - previousLlmMessage.content.push(toolResultContent); - - return previousLlmMessages; } + /** + * If the previous message is a `user` message, then append + * the tool result content to the previous message to avoid + * consecutive `user` messages. + */ + previousLlmMessage.content.push(toolResultContent); + return previousLlmMessages; - }, - [] as LlmMessage[], - ); + } + + return previousLlmMessages; + }, [] as LlmMessage[]); }; diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/log-llm-request.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/log-llm-request.ts index 246c30e1f99..ad712c5b286 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/log-llm-request.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/log-llm-request.ts @@ -60,9 +60,7 @@ export const logLlmServerError = (log: LlmServerErrorLog) => { } }; -export const logLlmRequest = ( - log: LlmLog & { transformedRequest?: Record }, -) => { +export const logLlmRequest = (log: LlmLog & { transformedRequest?: Record }) => { const orderedLog = { requestId: log.requestId, finalized: log.finalized, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/types.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/types.ts index bd157334a3a..cecd57403ab 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/types.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/types.ts @@ -27,10 +27,7 @@ export type LlmToolDefinition = { }; export type CommonLlmParams = { - model: - | PermittedAnthropicModel - | PermittedOpenAiModel - | PermittedGoogleAiModel; + model: PermittedAnthropicModel | PermittedOpenAiModel | PermittedGoogleAiModel; tools?: LlmToolDefinition[]; systemPrompt?: string; messages: LlmMessage[]; @@ -42,37 +39,31 @@ export type CommonLlmParams = { }; }; -export type GoogleAiParams = - CommonLlmParams & { - model: PermittedGoogleAiModel; - previousInvalidResponses?: (GenerateContentResponse & { - requestTime: number; - })[]; - }; +export type GoogleAiParams = CommonLlmParams & { + model: PermittedGoogleAiModel; + previousInvalidResponses?: (GenerateContentResponse & { + requestTime: number; + })[]; +}; -export type AnthropicLlmParams = - CommonLlmParams & { - model: PermittedAnthropicModel; - maxTokens?: number; - previousInvalidResponses?: (AnthropicMessagesCreateResponse & { - requestTime: number; - })[]; - } & Omit< - AnthropicMessagesCreateParams, - "tools" | "max_tokens" | "system" | "messages" | "tool_choice" - >; - -export type OpenAiLlmParams = - CommonLlmParams & { - model: PermittedOpenAiModel; - trimMessageAtIndex?: number; - previousInvalidResponses?: (OpenAI.ChatCompletion & { - requestTime: number; - })[]; - } & Omit< - OpenAI.ChatCompletionCreateParams, - "tools" | "messages" | "tool_choice" - >; +export type AnthropicLlmParams = CommonLlmParams & { + model: PermittedAnthropicModel; + maxTokens?: number; + previousInvalidResponses?: (AnthropicMessagesCreateResponse & { + requestTime: number; + })[]; +} & Omit< + AnthropicMessagesCreateParams, + "tools" | "max_tokens" | "system" | "messages" | "tool_choice" + >; + +export type OpenAiLlmParams = CommonLlmParams & { + model: PermittedOpenAiModel; + trimMessageAtIndex?: number; + previousInvalidResponses?: (OpenAI.ChatCompletion & { + requestTime: number; + })[]; +} & Omit; export type LlmParams = | AnthropicLlmParams @@ -105,13 +96,11 @@ export type LlmServerErrorLog = LlmRequestMetadata & { secondsTaken: number; }; -export const isLlmParamsAnthropicLlmParams = ( - params: LlmParams, -): params is AnthropicLlmParams => isPermittedAnthropicModel(params.model); +export const isLlmParamsAnthropicLlmParams = (params: LlmParams): params is AnthropicLlmParams => + isPermittedAnthropicModel(params.model); -export const isLlmParamsGoogleAiParams = ( - params: LlmParams, -): params is GoogleAiParams => isPermittedGoogleAiModel(params.model); +export const isLlmParamsGoogleAiParams = (params: LlmParams): params is GoogleAiParams => + isPermittedGoogleAiModel(params.model); export type AnthropicResponse = Omit< AnthropicMessagesCreateResponse, @@ -122,24 +111,15 @@ export type AnthropicResponse = Omit< })[]; }; -export type OpenAiResponse = Omit< - OpenAI.ChatCompletion, - "usage" | "choices" | "object" -> & { +export type OpenAiResponse = Omit & { invalidResponses: (OpenAI.ChatCompletion & { requestTime: number })[]; }; -export type GoogleAiResponse = Omit< - GenerateContentResponse, - "usage" | "candidates" -> & { +export type GoogleAiResponse = Omit & { invalidResponses: (GenerateContentResponse & { requestTime: number })[]; }; -export type ParsedLlmToolCall< - ToolName extends string = string, - Input extends object = object, -> = { +export type ParsedLlmToolCall = { id: string; name: ToolName; input: Input; @@ -156,12 +136,7 @@ export type ParsedLlmToolCall< * - `"content_filters"`: if content was omitted due to a flag from our content filters (OpenAI specific) * - `"stop_sequence"`: one of your provided custom `stop_sequences` was generated (Anthropic specific) */ -export type LlmStopReason = - | "stop" - | "tool_use" - | "length" - | "content_filter" - | "stop_sequence"; +export type LlmStopReason = "stop" | "tool_use" | "length" | "content_filter" | "stop_sequence"; export type LlmUsage = { /** @@ -186,9 +161,7 @@ export type LlmErrorResponse = provider: LlmProvider; lastRequestTime: number; totalRequestTime: number; - invalidResponses: - | AnthropicResponse["invalidResponses"] - | OpenAiResponse["invalidResponses"]; + invalidResponses: AnthropicResponse["invalidResponses"] | OpenAiResponse["invalidResponses"]; usage: LlmUsage; } | { @@ -230,11 +203,7 @@ export type LlmResponse = lastRequestTime: number; totalRequestTime: number; message: LlmAssistantMessage< - T["tools"] extends (infer U)[] - ? U extends { name: infer N } - ? N - : never - : string + T["tools"] extends (infer U)[] ? (U extends { name: infer N } ? N : never) : string >; } & (T extends AnthropicLlmParams ? Omit diff --git a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/validation.ts b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/validation.ts index a06fac84058..9cc44cc8db3 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/validation.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/get-llm-response/validation.ts @@ -26,16 +26,13 @@ export const sanitizeInputBeforeValidation = (params: { "properties" in params.input && typeof params.input.properties === "object" && params.input.properties !== null && - !Object.keys(toolDefinition.inputSchema.properties ?? {}).includes( - "properties", - ) + !Object.keys(toolDefinition.inputSchema.properties ?? {}).includes("properties") ? params.input.properties : params.input; if (toolDefinition.sanitizeInputBeforeValidation) { try { - const sanitizedInput = - toolDefinition.sanitizeInputBeforeValidation(input); + const sanitizedInput = toolDefinition.sanitizeInputBeforeValidation(input); return sanitizedInput; } catch { @@ -45,9 +42,7 @@ export const sanitizeInputBeforeValidation = (params: { * input. In this case, we can proceed to the JSON Schema validation * step which should produce a more informative error message for the LLM. */ - logger.error( - `Error sanitizing input before validation: ${stringify(input)}`, - ); + logger.error(`Error sanitizing input before validation: ${stringify(input)}`); } } @@ -69,9 +64,7 @@ const getValidator = () => { return _ajv; }; -const applyAdditionalPropertiesFalseToSchema = (params: { - schema: JSONSchema; -}): JSONSchema => { +const applyAdditionalPropertiesFalseToSchema = (params: { schema: JSONSchema }): JSONSchema => { const { schema } = params; if (typeof schema !== "object") { diff --git a/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output-optimize/judge-test-data.ts b/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output-optimize/judge-test-data.ts index f211ec0dddc..07a56774cf2 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output-optimize/judge-test-data.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output-optimize/judge-test-data.ts @@ -19,8 +19,7 @@ type JudgeTest = { expectedCorrections: CorrectedValue[]; nonInferrableFieldPaths: string[][]; }; - inputData: Required> & - Pick; + inputData: Required> & Pick; }; const baseJsonPath = ["content", "0", "input", "documentMetadata"]; @@ -84,14 +83,12 @@ export const judgeTestData: JudgeTest[] = [ { jsonPath: generateJsonPath(["study-arm"]), type: "correct-missing", - isProvidedValueCorrect: (value) => - Array.isArray(value) && value.length > 0, + isProvidedValueCorrect: (value) => Array.isArray(value) && value.length > 0, }, { jsonPath: generateJsonPath(["outcome-measure"]), type: "correct-missing", - isProvidedValueCorrect: (value) => - Array.isArray(value) && value.length > 0, + isProvidedValueCorrect: (value) => Array.isArray(value) && value.length > 0, }, { jsonPath: generateJsonPath(["authors"]), @@ -112,10 +109,7 @@ export const judgeTestData: JudgeTest[] = [ return false; } - if ( - !name.includes("Sarah Young") && - !name.includes("Lori McDermott") - ) { + if (!name.includes("Sarah Young") && !name.includes("Lori McDermott")) { return false; } } @@ -145,14 +139,12 @@ export const judgeTestData: JudgeTest[] = [ properties: { "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/": "study_record_ISRCTN15438979_2025-01-20.pdf", - "https://hash.ai/@h/types/property-type/file-storage-region/": - "local", + "https://hash.ai/@h/types/property-type/file-storage-region/": "local", "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": "study_record_ISRCTN15438979_2025-01-20.pdf", "https://hash.ai/@h/types/property-type/file-storage-endpoint/": "http://localhost:9000", - "https://hash.ai/@h/types/property-type/file-storage-provider/": - "AWS_S3", + "https://hash.ai/@h/types/property-type/file-storage-provider/": "AWS_S3", "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": "http://localhost:5001/file/files/f89989c3-c5b9-4662-9cff-651384f4a0da~4043537b-6fc0-4d1b-95b5-2c84d03e9bbf/0050a41f-113e-409c-a54c-d46d89ba103b/study_record_ISRCTN15438979_2025-01-20.pdf", "https://hash.ai/@h/types/property-type/file-storage-key/": @@ -160,8 +152,7 @@ export const judgeTestData: JudgeTest[] = [ "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/": 45633, "https://hash.ai/@h/types/property-type/upload-completed-at/": "2025-01-31T18:20:01.069Z", - "https://hash.ai/@h/types/property-type/file-storage-bucket/": - "dev-hash-bucket", + "https://hash.ai/@h/types/property-type/file-storage-bucket/": "dev-hash-bucket", "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": "application/pdf", "https://hash.ai/@h/types/property-type/file-storage-force-path-style/": true, @@ -227,8 +218,7 @@ export const judgeTestData: JudgeTest[] = [ ], "actual-study-start-date": "2024-07-01", isrctn: "ISRCTN15438979", - entityTypeId: - "https://hash.ai/@h/types/entity-type/study-record/v/1", + entityTypeId: "https://hash.ai/@h/types/entity-type/study-record/v/1", location: "Canada", "study-type": "Safety, Efficacy", doi: "10.1186/ISRCTN15438979", @@ -268,9 +258,7 @@ export const judgeTestData: JudgeTest[] = [ properties: { entityTypeId: { type: "STRING", - enum: [ - "https://hash.ai/@h/types/entity-type/study-record/v/1", - ], + enum: ["https://hash.ai/@h/types/entity-type/study-record/v/1"], }, objective: { type: "array", @@ -307,8 +295,7 @@ export const judgeTestData: JudgeTest[] = [ isrctn: { $id: "https://hash.ai/@h/types/property-type/isrctn/v/1", title: "ISRCTN", - description: - "The ISRCTN Registry identifier for something.", + description: "The ISRCTN Registry identifier for something.", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/isrctn/v/1", @@ -335,8 +322,7 @@ export const judgeTestData: JudgeTest[] = [ doi: { $id: "https://hash.ai/@h/types/property-type/doi/v/1", title: "DOI", - description: - "The Digital Object Identifier (DOI) of an object", + description: "The Digital Object Identifier (DOI) of an object", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/doi/v/1", @@ -356,8 +342,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://hash.ai/@h/types/data-type/uri/v/1", title: "URI", - description: - "A unique identifier for a resource (e.g. a URL, or URN).", + description: "A unique identifier for a resource (e.g. a URL, or URN).", type: "string", format: "uri", }, @@ -419,8 +404,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", title: "Text", - description: - "An ordered sequence of characters", + description: "An ordered sequence of characters", type: "string", }, ], @@ -434,8 +418,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", title: "Text", - description: - "An ordered sequence of characters", + description: "An ordered sequence of characters", type: "string", }, ], @@ -449,8 +432,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", title: "Text", - description: - "An ordered sequence of characters", + description: "An ordered sequence of characters", type: "string", }, ], @@ -516,8 +498,7 @@ export const judgeTestData: JudgeTest[] = [ items: { $id: "https://hash.ai/@h/types/property-type/outcome-measure/v/1", title: "Outcome Measure", - description: - "A measurement used to evaluate the outcome of a trial", + description: "A measurement used to evaluate the outcome of a trial", oneOf: [ { properties: { @@ -530,8 +511,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", title: "Text", - description: - "An ordered sequence of characters", + description: "An ordered sequence of characters", type: "string", }, ], @@ -545,8 +525,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", title: "Text", - description: - "An ordered sequence of characters", + description: "An ordered sequence of characters", type: "string", }, ], @@ -560,8 +539,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", title: "Text", - description: - "An ordered sequence of characters", + description: "An ordered sequence of characters", type: "string", }, ], @@ -656,8 +634,7 @@ export const judgeTestData: JudgeTest[] = [ "actual-enrollment": { $id: "https://hash.ai/@h/types/property-type/actual-enrollment/v/1", title: "Actual Enrollment", - description: - "The actual number of participants enrolled in something.", + description: "The actual number of participants enrolled in something.", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/integer/v/1", @@ -721,8 +698,7 @@ export const judgeTestData: JudgeTest[] = [ location: { $id: "https://hash.ai/@h/types/property-type/location/v/1", title: "Location", - description: - "A location for something, expressed as a single string", + description: "A location for something, expressed as a single string", oneOf: [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", @@ -753,8 +729,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", title: "Number", - description: - "An arithmetical value (in the Real number system)", + description: "An arithmetical value (in the Real number system)", type: "number", }, ], @@ -762,8 +737,7 @@ export const judgeTestData: JudgeTest[] = [ "publication-year": { $id: "https://hash.ai/@h/types/property-type/publication-year/v/1", title: "Publication Year", - description: - "The year in which something was first published.", + description: "The year in which something was first published.", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/calendar-year/v/1", @@ -787,12 +761,7 @@ export const judgeTestData: JudgeTest[] = [ ], }, }, - required: [ - "methodology", - "objective", - "title", - "entityTypeId", - ], + required: ["methodology", "objective", "title", "entityTypeId"], }, { type: "object", @@ -823,8 +792,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", title: "Number", - description: - "An arithmetical value (in the Real number system)", + description: "An arithmetical value (in the Real number system)", type: "number", }, ], @@ -832,8 +800,7 @@ export const judgeTestData: JudgeTest[] = [ "publication-year": { $id: "https://hash.ai/@h/types/property-type/publication-year/v/1", title: "Publication Year", - description: - "The year in which something was first published.", + description: "The year in which something was first published.", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/calendar-year/v/1", @@ -865,9 +832,7 @@ export const judgeTestData: JudgeTest[] = [ properties: { entityTypeId: { type: "STRING", - enum: [ - "https://hash.ai/@h/types/entity-type/academic-paper/v/1", - ], + enum: ["https://hash.ai/@h/types/entity-type/academic-paper/v/1"], }, "doi-link": { $id: "https://hash.ai/@h/types/property-type/doi-link/v/1", @@ -878,8 +843,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://hash.ai/@h/types/data-type/uri/v/1", title: "URI", - description: - "A unique identifier for a resource (e.g. a URL, or URN).", + description: "A unique identifier for a resource (e.g. a URL, or URN).", type: "string", format: "uri", }, @@ -916,8 +880,7 @@ export const judgeTestData: JudgeTest[] = [ doi: { $id: "https://hash.ai/@h/types/property-type/doi/v/1", title: "DOI", - description: - "The Digital Object Identifier (DOI) of an object", + description: "The Digital Object Identifier (DOI) of an object", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/doi/v/1", @@ -976,8 +939,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", title: "Number", - description: - "An arithmetical value (in the Real number system)", + description: "An arithmetical value (in the Real number system)", type: "number", }, ], @@ -985,8 +947,7 @@ export const judgeTestData: JudgeTest[] = [ "publication-year": { $id: "https://hash.ai/@h/types/property-type/publication-year/v/1", title: "Publication Year", - description: - "The year in which something was first published.", + description: "The year in which something was first published.", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/calendar-year/v/1", @@ -1010,8 +971,7 @@ export const judgeTestData: JudgeTest[] = [ isbn: { $id: "https://hash.ai/@h/types/property-type/isbn/v/1", title: "ISBN", - description: - "The International Standard Book Number (ISBN) of a book", + description: "The International Standard Book Number (ISBN) of a book", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/isbn/v/1", @@ -1043,8 +1003,7 @@ export const judgeTestData: JudgeTest[] = [ { $id: "https://blockprotocol.org/@blockprotocol/types/data-type/number/v/1", title: "Number", - description: - "An arithmetical value (in the Real number system)", + description: "An arithmetical value (in the Real number system)", type: "number", }, ], @@ -1052,8 +1011,7 @@ export const judgeTestData: JudgeTest[] = [ "publication-year": { $id: "https://hash.ai/@h/types/property-type/publication-year/v/1", title: "Publication Year", - description: - "The year in which something was first published.", + description: "The year in which something was first published.", oneOf: [ { $id: "https://hash.ai/@h/types/data-type/calendar-year/v/1", diff --git a/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output.optimize.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output.optimize.ai.test.ts index bb720ad0ffc..839ce8fbc4c 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output.optimize.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-output.optimize.ai.test.ts @@ -8,151 +8,137 @@ import { test } from "vitest"; import { stringifyPropertyValue } from "@local/hash-isomorphic-utils/stringify-property-value"; import { judgeTestData } from "./judge-ai-output-optimize/judge-test-data.js"; -import { - judgeAiOutputs, - type JudgeCorrection, - judgeSystemPrompt, -} from "./judge-ai-outputs.js"; +import { judgeAiOutputs, type JudgeCorrection, judgeSystemPrompt } from "./judge-ai-outputs.js"; import { optimizeSystemPrompt } from "./optimize-system-prompt.js"; import type { LlmParams } from "./get-llm-response/types.js"; import type { MetricDefinition } from "./optimize-system-prompt/types.js"; -const metrics: MetricDefinition[] = judgeTestData.map( - (testItem): MetricDefinition => { - return { - name: testItem.testName, - description: "", - executeMetric: async ({ testingParams }) => { - const { inputData, evaluation } = testItem; - - const { - score: judgeProvidedScore, - feedback: judgeProvidedFeedback, - corrections, - } = await judgeAiOutputs({ - exchangeToReview: inputData, - judgeModel: testingParams.model, - judgeAdditionalInstructions: "", - testingParams, - }); - - let score = 0.5; - - const { - alreadyCorrectFieldPaths, - nonInferrableFieldPaths, - expectedCorrections, - } = evaluation; - - const rewardPerCorrection = 0.5 / expectedCorrections.length; - const penaltyPerMistake = - 0.5 / - (alreadyCorrectFieldPaths.length + nonInferrableFieldPaths.length); - - const unhandledCorrections: JudgeCorrection[] = []; - - const mistakenlyCorrectedPaths: string[] = []; - const mistakenlyInferredPaths: string[] = []; - const missingCorrectionValues: string[] = []; - const wrongValueCorrections: string[] = []; - - const validCorrections: string[] = []; - - const feedback = ""; - - for (const correction of corrections) { - const isAlreadyCorrect = evaluation.alreadyCorrectFieldPaths.some( - (jsonPath) => isEqual(correction.jsonPath, jsonPath), - ); +const metrics: MetricDefinition[] = judgeTestData.map((testItem): MetricDefinition => { + return { + name: testItem.testName, + description: "", + executeMetric: async ({ testingParams }) => { + const { inputData, evaluation } = testItem; - if (isAlreadyCorrect) { - mistakenlyCorrectedPaths.push(correction.jsonPath.join(".")); - score -= penaltyPerMistake; - continue; - } + const { + score: judgeProvidedScore, + feedback: judgeProvidedFeedback, + corrections, + } = await judgeAiOutputs({ + exchangeToReview: inputData, + judgeModel: testingParams.model, + judgeAdditionalInstructions: "", + testingParams, + }); - const isNonInferrable = evaluation.nonInferrableFieldPaths.some( - (jsonPath) => isEqual(correction.jsonPath, jsonPath), - ); - if (isNonInferrable) { - mistakenlyInferredPaths.push(correction.jsonPath.join(".")); - score -= penaltyPerMistake; - continue; - } - - const applicableCorrection = evaluation.expectedCorrections.find( - (expectedCorrection) => - isEqual(expectedCorrection.jsonPath, correction.jsonPath) && - expectedCorrection.type === correction.correctionType, - ); + let score = 0.5; + + const { alreadyCorrectFieldPaths, nonInferrableFieldPaths, expectedCorrections } = evaluation; + + const rewardPerCorrection = 0.5 / expectedCorrections.length; + const penaltyPerMistake = + 0.5 / (alreadyCorrectFieldPaths.length + nonInferrableFieldPaths.length); + + const unhandledCorrections: JudgeCorrection[] = []; - if (!applicableCorrection) { - unhandledCorrections.push(correction); - continue; - } - - if (applicableCorrection.type === "delete-unfounded") { - score += rewardPerCorrection; - validCorrections.push(correction.jsonPath.join(".")); - continue; - } - - if (!correction.correctValue) { - missingCorrectionValues.push(correction.jsonPath.join(".")); - /** - * technically applying penalties here lets the score go below 0, - * because penaltyPerMistake doesn't take account of provided corrections that are wrong. - * But for comparing results the relative score rather than the absolute score is what matters. - */ - score -= penaltyPerMistake; - continue; - } - - const providedValueIsCorrect = - applicableCorrection.isProvidedValueCorrect( - correction.correctValue, - ); - - if (providedValueIsCorrect) { - validCorrections.push(correction.jsonPath.join(".")); - score += rewardPerCorrection; - } else { - wrongValueCorrections.push( - `${correction.jsonPath.join(".")}: ${stringifyPropertyValue( - correction.correctValue, - )}`, - ); - /** - * technically applying penalties here lets the score go below 0, - * because penaltyPerMistake doesn't take account of provided corrections that are wrong. - * But for comparing results the relative score rather than the absolute score is what matters. - */ - score -= penaltyPerMistake; - } + const mistakenlyCorrectedPaths: string[] = []; + const mistakenlyInferredPaths: string[] = []; + const missingCorrectionValues: string[] = []; + const wrongValueCorrections: string[] = []; + + const validCorrections: string[] = []; + + const feedback = ""; + + for (const correction of corrections) { + const isAlreadyCorrect = evaluation.alreadyCorrectFieldPaths.some((jsonPath) => + isEqual(correction.jsonPath, jsonPath), + ); + + if (isAlreadyCorrect) { + mistakenlyCorrectedPaths.push(correction.jsonPath.join(".")); + score -= penaltyPerMistake; + continue; } - const additionalInfo = { - judgeProvidedFeedback, - judgeProvidedScore, - mistakenlyCorrectedPaths, - mistakenlyInferredPaths, - missingCorrectionValues, - wrongValueCorrections, - validCorrections, - unhandledCorrections: JSON.stringify(unhandledCorrections), - }; - - return { - score: Math.max(score, 0), - testingParams, - naturalLanguageReport: feedback, - additionalInfo, - }; - }, - }; - }, -); + const isNonInferrable = evaluation.nonInferrableFieldPaths.some((jsonPath) => + isEqual(correction.jsonPath, jsonPath), + ); + if (isNonInferrable) { + mistakenlyInferredPaths.push(correction.jsonPath.join(".")); + score -= penaltyPerMistake; + continue; + } + + const applicableCorrection = evaluation.expectedCorrections.find( + (expectedCorrection) => + isEqual(expectedCorrection.jsonPath, correction.jsonPath) && + expectedCorrection.type === correction.correctionType, + ); + + if (!applicableCorrection) { + unhandledCorrections.push(correction); + continue; + } + + if (applicableCorrection.type === "delete-unfounded") { + score += rewardPerCorrection; + validCorrections.push(correction.jsonPath.join(".")); + continue; + } + + if (!correction.correctValue) { + missingCorrectionValues.push(correction.jsonPath.join(".")); + /** + * technically applying penalties here lets the score go below 0, + * because penaltyPerMistake doesn't take account of provided corrections that are wrong. + * But for comparing results the relative score rather than the absolute score is what matters. + */ + score -= penaltyPerMistake; + continue; + } + + const providedValueIsCorrect = applicableCorrection.isProvidedValueCorrect( + correction.correctValue, + ); + + if (providedValueIsCorrect) { + validCorrections.push(correction.jsonPath.join(".")); + score += rewardPerCorrection; + } else { + wrongValueCorrections.push( + `${correction.jsonPath.join(".")}: ${stringifyPropertyValue(correction.correctValue)}`, + ); + /** + * technically applying penalties here lets the score go below 0, + * because penaltyPerMistake doesn't take account of provided corrections that are wrong. + * But for comparing results the relative score rather than the absolute score is what matters. + */ + score -= penaltyPerMistake; + } + } + + const additionalInfo = { + judgeProvidedFeedback, + judgeProvidedScore, + mistakenlyCorrectedPaths, + mistakenlyInferredPaths, + missingCorrectionValues, + wrongValueCorrections, + validCorrections, + unhandledCorrections: JSON.stringify(unhandledCorrections), + }; + + return { + score: Math.max(score, 0), + testingParams, + naturalLanguageReport: feedback, + additionalInfo, + }; + }, + }; +}); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-outputs.ts b/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-outputs.ts index b9da4de9fcf..12f67450a6b 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-outputs.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/judge-ai-outputs.ts @@ -204,11 +204,7 @@ const judgeTool: LlmToolDefinition = { jsonPath: { type: "array", items: { type: "string" } }, correctionType: { type: "string", - enum: [ - "correct-missing", - "correct-incorrect", - "delete-unfounded", - ], + enum: ["correct-missing", "correct-incorrect", "delete-unfounded"], }, correctValue: { anyOf: [ @@ -257,9 +253,7 @@ export const judgeAiOutputs = async ({ if (fileMessages.length > 0) { if (!isPermittedGoogleAiModel(judgeModel)) { - throw new Error( - "Judge must be Google AI model in order to provide files to it.", - ); + throw new Error("Judge must be Google AI model in order to provide files to it."); } judgePrompt.content.push(...fileMessages); @@ -275,8 +269,7 @@ export const judgeAiOutputs = async ({ throw new Error("Last message must be from the AI"); } - const { flowEntityId, stepId, userAuthentication, webId } = - await getFlowContext(); + const { flowEntityId, stepId, userAuthentication, webId } = await getFlowContext(); const judgeResponse = await getLlmResponse( { @@ -341,23 +334,15 @@ export const judgeAiOutputs = async ({ const errors: string[] = []; for (const correction of toolCall.input.corrections) { - const existingValue = get(lastAiMessage, correction.jsonPath) as - | PropertyValue - | undefined; - - if ( - correction.correctionType !== "correct-missing" && - existingValue === undefined - ) { + const existingValue = get(lastAiMessage, correction.jsonPath) as PropertyValue | undefined; + + if (correction.correctionType !== "correct-missing" && existingValue === undefined) { errors.push( `You provided a correction of type ${correction.correctionType} at path ${correction.jsonPath.join( ".", )} but there is no value at that path. Value must exist to be corrected or deleted. If you are providing a value that was missed, used the 'correct-missing' correction type.`, ); - } else if ( - correction.correctionType === "correct-missing" && - existingValue !== undefined - ) { + } else if (correction.correctionType === "correct-missing" && existingValue !== undefined) { errors.push( `You provided a correction of type ${correction.correctionType} at path ${correction.jsonPath.join( ".", diff --git a/apps/hash-ai-worker-ts/src/activities/shared/log-progress.ts b/apps/hash-ai-worker-ts/src/activities/shared/log-progress.ts index 3c1a443b237..f790ca19d0f 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/log-progress.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/log-progress.ts @@ -41,11 +41,7 @@ const sendLogSignal = debounce( * Likely the workflow doesn't exist because it has been cancelled * @todo H-2545: Graceful workflow cancellation */ - logger.error( - `Could not send logs for workflowId ${workflowId}: ${ - (err as Error).message - }`, - ); + logger.error(`Could not send logs for workflowId ${workflowId}: ${(err as Error).message}`); } }, 1_000, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/map-action-input-entities-to-entities.ts b/apps/hash-ai-worker-ts/src/activities/shared/map-action-input-entities-to-entities.ts index 161b5a67b78..76800a9210a 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/map-action-input-entities-to-entities.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/map-action-input-entities-to-entities.ts @@ -13,10 +13,7 @@ import type { export const mapActionInputEntitiesToEntities = async (params: { actorId: ActorEntityUuid; graphApiClient: GraphApi; - inputEntities: - | SerializedEntity[] - | PersistedEntityMetadata[] - | PersistedEntitiesMetadata; + inputEntities: SerializedEntity[] | PersistedEntityMetadata[] | PersistedEntitiesMetadata; }): Promise => { const { actorId, graphApiClient, inputEntities } = params; @@ -24,9 +21,7 @@ export const mapActionInputEntitiesToEntities = async (params: { const directEntities: HashEntity[] = []; const inputEntitiesArray = - "persistedEntities" in inputEntities - ? inputEntities.persistedEntities - : inputEntities; + "persistedEntities" in inputEntities ? inputEntities.persistedEntities : inputEntities; for (const inputEntity of inputEntitiesArray) { if ("operation" in inputEntity) { @@ -47,10 +42,7 @@ export const mapActionInputEntitiesToEntities = async (params: { { filter: { any: entityIdsToFetch.map((entityId) => ({ - equal: [ - { path: ["uuid"] }, - { parameter: extractEntityUuidFromEntityId(entityId) }, - ], + equal: [{ path: ["uuid"] }, { parameter: extractEntityUuidFromEntityId(entityId) }], })), }, temporalAxes: currentTimeInstantTemporalAxes, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.optimize.ai.test.ts b/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.optimize.ai.test.ts index 25efd62d15c..9a01fa66068 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.optimize.ai.test.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.optimize.ai.test.ts @@ -16,10 +16,7 @@ import { } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { stringifyPropertyValue } from "@local/hash-isomorphic-utils/stringify-property-value"; -import { - matchExistingEntity, - matchExistingEntitySystemPrompt, -} from "./match-existing-entity.js"; +import { matchExistingEntity, matchExistingEntitySystemPrompt } from "./match-existing-entity.js"; import { optimizeSystemPrompt } from "./optimize-system-prompt.js"; import type { LlmParams } from "./get-llm-response/types.js"; @@ -40,8 +37,7 @@ const emptyMetadataObject: PropertyObjectMetadata = { const testWebId = generateUuid() as WebId; -const generateEntityId = () => - entityIdFromComponents(testWebId, generateUuid() as EntityUuid); +const generateEntityId = () => entityIdFromComponents(testWebId, generateUuid() as EntityUuid); type MatchExistingEntityTest = { testName: string; @@ -73,8 +69,7 @@ const matchTestData: MatchExistingEntityTest[] = [ }, propertiesMetadata: emptyMetadataObject, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "Bill Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "Bill Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "An American businessman and philanthropist best known for co-founding the software company Microsoft Corporation.", }), @@ -87,8 +82,7 @@ const matchTestData: MatchExistingEntityTest[] = [ }, propertiesMetadata: emptyMetadataObject, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "William Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "William Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "A professional basketball player, he was the first African American player signed to the National Basketball League.", }), @@ -101,8 +95,7 @@ const matchTestData: MatchExistingEntityTest[] = [ entityId: williamGatesBasketballUuid, propertiesMetadata: emptyMetadataObject, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "William Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "William Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "An American former college basketball player, subject of the 1994 documentary film Hoop Dreams.", }), @@ -113,29 +106,26 @@ const matchTestData: MatchExistingEntityTest[] = [ editionSources: [], propertiesMetadata: { value: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - { - metadata: { - dataTypeId: blockProtocolDataTypes.text.dataTypeId, - provenance: { - sources: [], - }, - } satisfies ValueMetadata, - }, - "https://blockprotocol.org/@blockprotocol/types/property-type/description/": - { - metadata: { - dataTypeId: blockProtocolDataTypes.text.dataTypeId, - provenance: { - sources: [], - }, - } satisfies ValueMetadata, - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": { + metadata: { + dataTypeId: blockProtocolDataTypes.text.dataTypeId, + provenance: { + sources: [], + }, + } satisfies ValueMetadata, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/description/": { + metadata: { + dataTypeId: blockProtocolDataTypes.text.dataTypeId, + provenance: { + sources: [], + }, + } satisfies ValueMetadata, + }, }), }, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "William Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "William Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "He founded Microsoft in Albuquerque, New Mexico.", }), @@ -156,8 +146,7 @@ const matchTestData: MatchExistingEntityTest[] = [ }, propertiesMetadata: emptyMetadataObject, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "William Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "William Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "He founded Microsoft in Albuquerque, New Mexico.", }), @@ -170,8 +159,7 @@ const matchTestData: MatchExistingEntityTest[] = [ }, propertiesMetadata: emptyMetadataObject, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "Bill Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "Bill Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "An American businessman and philanthropist best known for co-founding the software company Microsoft Corporation.", }), @@ -184,8 +172,7 @@ const matchTestData: MatchExistingEntityTest[] = [ }, propertiesMetadata: emptyMetadataObject, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "William Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "William Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "A professional basketball player, he was the first African American player signed to the National Basketball League.", }), @@ -196,29 +183,26 @@ const matchTestData: MatchExistingEntityTest[] = [ editionSources: [], propertiesMetadata: { value: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - { - metadata: { - dataTypeId: blockProtocolDataTypes.text.dataTypeId, - provenance: { - sources: [], - }, - } satisfies ValueMetadata, - }, - "https://blockprotocol.org/@blockprotocol/types/property-type/description/": - { - metadata: { - dataTypeId: blockProtocolDataTypes.text.dataTypeId, - provenance: { - sources: [], - }, - } satisfies ValueMetadata, - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": { + metadata: { + dataTypeId: blockProtocolDataTypes.text.dataTypeId, + provenance: { + sources: [], + }, + } satisfies ValueMetadata, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/description/": { + metadata: { + dataTypeId: blockProtocolDataTypes.text.dataTypeId, + provenance: { + sources: [], + }, + } satisfies ValueMetadata, + }, }), }, properties: brandPropertyObject({ - "https://blockprotocol.org/@blockprotocol/types/property-type/name/": - "William Gates", + "https://blockprotocol.org/@blockprotocol/types/property-type/name/": "William Gates", "https://blockprotocol.org/@blockprotocol/types/property-type/description/": "An American former college basketball player, subject of the 1994 documentary film Hoop Dreams. He never played professionally.", }), @@ -234,9 +218,7 @@ const matchTestData: MatchExistingEntityTest[] = [ { entityId: ceoStarted2020Uuid, metadata: { - entityTypeIds: [ - "https://hash.ai/@hash/types/entity-type/worked-at/v/1", - ], + entityTypeIds: ["https://hash.ai/@hash/types/entity-type/worked-at/v/1"], provenance: { edition: { sources: [] } }, }, properties: { @@ -248,9 +230,7 @@ const matchTestData: MatchExistingEntityTest[] = [ { entityId: ceoStarted2022Uuid, metadata: { - entityTypeIds: [ - "https://hash.ai/@hash/types/entity-type/worked-at/v/1", - ], + entityTypeIds: ["https://hash.ai/@hash/types/entity-type/worked-at/v/1"], provenance: { edition: { sources: [] } }, }, properties: { @@ -261,9 +241,7 @@ const matchTestData: MatchExistingEntityTest[] = [ ], newEntity: { editionSources: [], - entityTypeIds: [ - "https://hash.ai/@hash/types/entity-type/worked-at/v/1", - ], + entityTypeIds: ["https://hash.ai/@hash/types/entity-type/worked-at/v/1"], properties: { [systemPropertyTypes.appliesFrom.propertyTypeBaseUrl]: "2024-02-11", }, @@ -291,9 +269,7 @@ const matchTestData: MatchExistingEntityTest[] = [ { entityId: generateEntityId(), metadata: { - entityTypeIds: [ - "https://hash.ai/@hash/types/entity-type/worked-at/v/1", - ], + entityTypeIds: ["https://hash.ai/@hash/types/entity-type/worked-at/v/1"], provenance: { edition: { sources: [] } }, }, properties: { @@ -304,9 +280,7 @@ const matchTestData: MatchExistingEntityTest[] = [ { entityId: ceoStarted2022Uuid, metadata: { - entityTypeIds: [ - "https://hash.ai/@hash/types/entity-type/worked-at/v/1", - ], + entityTypeIds: ["https://hash.ai/@hash/types/entity-type/worked-at/v/1"], provenance: { edition: { sources: [] } }, }, properties: { @@ -318,9 +292,7 @@ const matchTestData: MatchExistingEntityTest[] = [ ], newEntity: { editionSources: [], - entityTypeIds: [ - "https://hash.ai/@hash/types/entity-type/worked-at/v/1", - ], + entityTypeIds: ["https://hash.ai/@hash/types/entity-type/worked-at/v/1"], properties: { [systemPropertyTypes.role.propertyTypeBaseUrl]: "CEO", [systemPropertyTypes.appliesFrom.propertyTypeBaseUrl]: "2024-02-11", @@ -350,79 +322,71 @@ const matchTestData: MatchExistingEntityTest[] = [ }, ]; -const metrics: MetricDefinition[] = matchTestData.map( - (testItem): MetricDefinition => { - return { - name: testItem.testName, - description: "", - executeMetric: async ({ testingParams }) => { - const { inputData, expectedMatchEntityId } = testItem; +const metrics: MetricDefinition[] = matchTestData.map((testItem): MetricDefinition => { + return { + name: testItem.testName, + description: "", + executeMetric: async ({ testingParams }) => { + const { inputData, expectedMatchEntityId } = testItem; - const match = await matchExistingEntity({ - entities: inputData, - isLink: false, - previousError: null, - testingParams, - }); + const match = await matchExistingEntity({ + entities: inputData, + isLink: false, + previousError: null, + testingParams, + }); - const reportedMatchId = match?.existingEntity.entityId ?? null; + const reportedMatchId = match?.existingEntity.entityId ?? null; - const score = reportedMatchId === expectedMatchEntityId ? 1 : 0; + const score = reportedMatchId === expectedMatchEntityId ? 1 : 0; - let naturalLanguageReport = ""; - if (!score) { - if (!expectedMatchEntityId) { - naturalLanguageReport = `No match was expected, but a match with entityId ${reportedMatchId} found.`; - } else if (reportedMatchId) { - naturalLanguageReport = `Expected match with entityId ${expectedMatchEntityId} but LLM matched with entityId ${reportedMatchId}.`; - } else { - naturalLanguageReport = `Expected match with entityId ${expectedMatchEntityId} but no match found.`; - } + let naturalLanguageReport = ""; + if (!score) { + if (!expectedMatchEntityId) { + naturalLanguageReport = `No match was expected, but a match with entityId ${reportedMatchId} found.`; + } else if (reportedMatchId) { + naturalLanguageReport = `Expected match with entityId ${expectedMatchEntityId} but LLM matched with entityId ${reportedMatchId}.`; } else { - naturalLanguageReport = `Correctly matched with entityId ${expectedMatchEntityId}.`; + naturalLanguageReport = `Expected match with entityId ${expectedMatchEntityId} but no match found.`; } + } else { + naturalLanguageReport = `Correctly matched with entityId ${expectedMatchEntityId}.`; + } - const mergedProperties = match?.newValues.properties; - const inputProperties = inputData.newEntity.properties; + const mergedProperties = match?.newValues.properties; + const inputProperties = inputData.newEntity.properties; - const propertiesWithMergedValues = typedEntries( - mergedProperties ?? {}, - ).filter(([key, value]) => { + const propertiesWithMergedValues = typedEntries(mergedProperties ?? {}).filter( + ([key, value]) => { return inputProperties[key] !== value; - }); + }, + ); - const additionalInfo = { - propertiesWithMergedValues: propertiesWithMergedValues.map( - ([key, value]) => `${key}: ${stringifyPropertyValue(value)}`, - ), - }; + const additionalInfo = { + propertiesWithMergedValues: propertiesWithMergedValues.map( + ([key, value]) => `${key}: ${stringifyPropertyValue(value)}`, + ), + }; - return { - score, - testingParams, - naturalLanguageReport, - additionalInfo, - }; - }, - }; - }, -); + return { + score, + testingParams, + naturalLanguageReport, + additionalInfo, + }; + }, + }; +}); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const baseDirectoryPath = path.join( - __dirname, - "/var/match-existing-entity-test", -); +const baseDirectoryPath = path.join(__dirname, "/var/match-existing-entity-test"); test( "Match new entity with existing entity", async () => { - const models: LlmParams["model"][] = [ - "claude-haiku-4-5-20251001", - "gpt-4o-2024-08-06", - ]; + const models: LlmParams["model"][] = ["claude-haiku-4-5-20251001", "gpt-4o-2024-08-06"]; await optimizeSystemPrompt({ attemptsPerPrompt: 8, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.ts b/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.ts index de3e882c424..ead21a4a8c4 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/match-existing-entity.ts @@ -314,10 +314,7 @@ const generateMatchExistingEntityTool = ( description: "The properties where you are merging the old and new value together. Do not include any properties which are not being merged – don't include any which don't appear in both the new and old entity, or which you are not changing from their new value.", properties: Object.fromEntries( - propertyNames.map((propertyName) => [ - propertyName, - { type: "string" }, - ]), + propertyNames.map((propertyName) => [propertyName, { type: "string" }]), ), }, }, @@ -472,12 +469,9 @@ export const matchExistingEntity = async ({ }): Promise> => { const { newEntity, potentialMatches } = entities; - const { flowEntityId, userAuthentication, stepId, webId } = - await getFlowContext(); + const { flowEntityId, userAuthentication, stepId, webId } = await getFlowContext(); - const tool = generateMatchExistingEntityTool( - Object.keys(newEntity.properties), - ); + const tool = generateMatchExistingEntityTool(Object.keys(newEntity.properties)); const userMessage = generateMatchExistingEntityUserMessage({ isLink, @@ -488,8 +482,7 @@ export const matchExistingEntity = async ({ const llmResponse = await getLlmResponse( { - systemPrompt: - testingParams?.systemPrompt ?? matchExistingEntitySystemPrompt, + systemPrompt: testingParams?.systemPrompt ?? matchExistingEntitySystemPrompt, tools: [tool], toolChoice: toolName, messages: [ @@ -551,8 +544,7 @@ export const matchExistingEntity = async ({ }); } - const { matchedEntityId, mergedProperties } = - firstToolCall.input as ExistingEntityReport; + const { matchedEntityId, mergedProperties } = firstToolCall.input as ExistingEntityReport; if (!matchedEntityId) { return null; @@ -579,9 +571,7 @@ export const matchExistingEntity = async ({ JSON.stringify(newEntity.propertiesMetadata), ) as typeof newEntity.propertiesMetadata; - for (const [baseUrl, valueFromNewEntity] of typedEntries( - newEntity.properties, - )) { + for (const [baseUrl, valueFromNewEntity] of typedEntries(newEntity.properties)) { const mergedValue = mergedProperties?.[baseUrl]; const newValue = mergedValue ?? valueFromNewEntity; @@ -603,15 +593,12 @@ export const matchExistingEntity = async ({ const newMetadataForProperty = newEntity.propertiesMetadata.value[baseUrl]; if (!newMetadataForProperty) { - throw new Error( - `No metadata provided for property changed at ${baseUrl}`, - ); + throw new Error(`No metadata provided for property changed at ${baseUrl}`); } if (mergedValue || newValue === match.properties[baseUrl]) { const existingSources = - existingMetadataForProperty && - isValueMetadata(existingMetadataForProperty) + existingMetadataForProperty && isValueMetadata(existingMetadataForProperty) ? (existingMetadataForProperty.metadata.provenance?.sources ?? []) : []; @@ -619,10 +606,7 @@ export const matchExistingEntity = async ({ ? (newMetadataForProperty.metadata.provenance?.sources ?? []) : []; - const mergedSources = deduplicateSources([ - ...existingSources, - ...newSources, - ]); + const mergedSources = deduplicateSources([...existingSources, ...newSources]); if (!isValueMetadata(newMetadataForProperty)) { throw new Error( @@ -651,9 +635,7 @@ export const matchExistingEntity = async ({ ]); const matchWithMergedValues = { - entityTypeIds: [ - ...new Set([...newEntity.entityTypeIds, ...match.metadata.entityTypeIds]), - ], + entityTypeIds: [...new Set([...newEntity.entityTypeIds, ...match.metadata.entityTypeIds])], editionSources: mergedEditionSources, properties: changedPropertiesWithMergedValues, propertyMetadata: metadataForChangedProperties, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/openai-client.ts b/apps/hash-ai-worker-ts/src/activities/shared/openai-client.ts index bba8d553ad6..c9a98e35992 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/openai-client.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/openai-client.ts @@ -11,9 +11,7 @@ const permittedOpenAiModels = [ export type PermittedOpenAiModel = (typeof permittedOpenAiModels)[number]; -export const isPermittedOpenAiModel = ( - model: string, -): model is PermittedOpenAiModel => +export const isPermittedOpenAiModel = (model: string): model is PermittedOpenAiModel => permittedOpenAiModels.includes(model as PermittedOpenAiModel); /** @see https://platform.openai.com/docs/models */ @@ -28,8 +26,7 @@ export const modelToContextWindow: Record = { export const isPermittedModel = ( model: OpenAI.ChatCompletionCreateParams["model"], -): model is PermittedOpenAiModel => - Object.keys(modelToContextWindow).includes(model); +): model is PermittedOpenAiModel => Object.keys(modelToContextWindow).includes(model); if (!process.env.OPENAI_API_KEY) { throw new Error("OPENAI_API_KEY environment variable not set."); diff --git a/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt.ts b/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt.ts index 663d7673e07..0d3f5267cc8 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt.ts @@ -37,25 +37,20 @@ const saveAllResultsToCSV = (params: { "Additional Info", ]; - const rows = results.flatMap( - ({ systemPrompt, iteration, metricResultsForModels }) => - metricResultsForModels.flatMap(({ model, metricResults }) => - metricResults.map(({ metric, result, responseTimeInSeconds }) => [ - iteration.toString(), - escapeCSV(model), - escapeCSV(systemPrompt), - escapeCSV(metric.name), - result.score.toString(), - `${responseTimeInSeconds.toString()} seconds`, - escapeCSV(result.naturalLanguageReport), - result.encounteredError - ? escapeCSV(result.encounteredError.status) - : "", - result.additionalInfo - ? escapeCSV(JSON.stringify(result.additionalInfo, null, 2)) - : "", - ]), - ), + const rows = results.flatMap(({ systemPrompt, iteration, metricResultsForModels }) => + metricResultsForModels.flatMap(({ model, metricResults }) => + metricResults.map(({ metric, result, responseTimeInSeconds }) => [ + iteration.toString(), + escapeCSV(model), + escapeCSV(systemPrompt), + escapeCSV(metric.name), + result.score.toString(), + `${responseTimeInSeconds.toString()} seconds`, + escapeCSV(result.naturalLanguageReport), + result.encounteredError ? escapeCSV(result.encounteredError.status) : "", + result.additionalInfo ? escapeCSV(JSON.stringify(result.additionalInfo, null, 2)) : "", + ]), + ), ); const csvContent = [headers, ...rows].map((row) => row.join(",")).join("\n"); @@ -73,9 +68,7 @@ const saveSummaryToCSV = (params: { const { results, directoryPath, filePrefix } = params; const models = results - .flatMap(({ metricResultsForModels }) => - metricResultsForModels.map(({ model }) => model), - ) + .flatMap(({ metricResultsForModels }) => metricResultsForModels.map(({ model }) => model)) .filter((value, index, all) => all.indexOf(value) === index); const metrics = results @@ -84,10 +77,7 @@ const saveSummaryToCSV = (params: { metricResults.map(({ metric }) => metric), ), ) - .filter( - (metric, index, all) => - all.findIndex(({ name }) => metric.name === name) === index, - ); + .filter((metric, index, all) => all.findIndex(({ name }) => metric.name === name) === index); const headers = [ "Iteration", @@ -97,47 +87,38 @@ const saveSummaryToCSV = (params: { ...metrics.map((metric) => metric.name), ]; - const rows = results.map( - ({ systemPrompt, iteration, metricResultsForModels }) => { - const modelAverageScores = models.map((model) => { - const scores = metricResultsForModels - .filter(({ model: currentModel }) => currentModel === model) - .flatMap(({ metricResults }) => - metricResults.map(({ result }) => result.score), - ); - - return scores.length > 0 - ? scores.reduce((acc, score) => acc + score, 0) / scores.length - : 0; - }); + const rows = results.map(({ systemPrompt, iteration, metricResultsForModels }) => { + const modelAverageScores = models.map((model) => { + const scores = metricResultsForModels + .filter(({ model: currentModel }) => currentModel === model) + .flatMap(({ metricResults }) => metricResults.map(({ result }) => result.score)); - const metricAverageScores = metrics.map((metric) => { - const scores = metricResultsForModels.flatMap(({ metricResults }) => { - const metricResultsForPrompt = metricResults.filter( - ({ metric: currentMetric }) => currentMetric.name === metric.name, - ); + return scores.length > 0 ? scores.reduce((acc, score) => acc + score, 0) / scores.length : 0; + }); - return metricResultsForPrompt.map(({ result }) => result.score); - }); + const metricAverageScores = metrics.map((metric) => { + const scores = metricResultsForModels.flatMap(({ metricResults }) => { + const metricResultsForPrompt = metricResults.filter( + ({ metric: currentMetric }) => currentMetric.name === metric.name, + ); - return scores.length > 0 - ? scores.reduce((acc, score) => acc + score, 0) / scores.length - : 0; + return metricResultsForPrompt.map(({ result }) => result.score); }); - const allScores = [...modelAverageScores, ...metricAverageScores]; - const overallScore = - allScores.reduce((acc, score) => acc + score, 0) / allScores.length; + return scores.length > 0 ? scores.reduce((acc, score) => acc + score, 0) / scores.length : 0; + }); - return [ - iteration.toString(), - escapeCSV(systemPrompt), - overallScore.toFixed(2), - ...modelAverageScores.map((score) => score.toFixed(2)), - ...metricAverageScores.map((score) => score.toFixed(2)), - ]; - }, - ); + const allScores = [...modelAverageScores, ...metricAverageScores]; + const overallScore = allScores.reduce((acc, score) => acc + score, 0) / allScores.length; + + return [ + iteration.toString(), + escapeCSV(systemPrompt), + overallScore.toFixed(2), + ...modelAverageScores.map((score) => score.toFixed(2)), + ...metricAverageScores.map((score) => score.toFixed(2)), + ]; + }); const csvContent = [headers, ...rows].map((row) => row.join(",")).join("\n"); @@ -173,8 +154,7 @@ const runMetricsForModels = async (params: { const endTime = new Date(); - const responseTimeInSeconds = - (endTime.getTime() - startTime.getTime()) / 1000; + const responseTimeInSeconds = (endTime.getTime() - startTime.getTime()) / 1000; iterationResults.push({ metric: metricDefinition, diff --git a/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt/improve-system-prompt.ts b/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt/improve-system-prompt.ts index 6ef67b5d80f..4c31b20a914 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt/improve-system-prompt.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/optimize-system-prompt/improve-system-prompt.ts @@ -37,29 +37,27 @@ const improveSystemPromptSystemPrompt = dedent(` Prompts with full, clear examples are generally better than prompts without examples. `); -const proposeSystemPromptToolDefinition: LlmToolDefinition<"proposeSystemPrompt"> = - { - name: "proposeSystemPrompt", - description: - "Propose an improved system prompt based on the previous system prompt and metric results.", - inputSchema: { - type: "object", - additionalProperties: false, - properties: { - improvedSystemPrompt: { - type: "string", - description: - "The improved system prompt that is expected to improve the LLM performance.", - }, - reasoning: { - type: "string", - description: - "A detailed explanation of why the proposed system prompt is expected to improve the LLM performance.", - }, +const proposeSystemPromptToolDefinition: LlmToolDefinition<"proposeSystemPrompt"> = { + name: "proposeSystemPrompt", + description: + "Propose an improved system prompt based on the previous system prompt and metric results.", + inputSchema: { + type: "object", + additionalProperties: false, + properties: { + improvedSystemPrompt: { + type: "string", + description: "The improved system prompt that is expected to improve the LLM performance.", + }, + reasoning: { + type: "string", + description: + "A detailed explanation of why the proposed system prompt is expected to improve the LLM performance.", }, - required: ["improvedSystemPrompt"], }, - }; + required: ["improvedSystemPrompt"], + }, +}; export const improveSystemPrompt = async (params: { previousSystemPrompt: string; @@ -76,10 +74,7 @@ export const improveSystemPrompt = async (params: { .flat(), ) .flat() - .filter( - (metric, index, all) => - all.findIndex(({ name }) => metric.name === name) === index, - ); + .filter((metric, index, all) => all.findIndex(({ name }) => metric.name === name) === index); const userMessage: LlmUserMessage = { role: "user", @@ -101,15 +96,14 @@ export const improveSystemPrompt = async (params: { */ results.map(({ systemPrompt, metricResultsForModels }) => ({ systemPrompt, - metricResultsForModels: metricResultsForModels.map( - ({ model, metricResults }) => - metricResults.map(({ metric, result }) => ({ - model, - metric: metric.name, - score: result.score, - report: result.naturalLanguageReport, - error: result.encounteredError, - })), + metricResultsForModels: metricResultsForModels.map(({ model, metricResults }) => + metricResults.map(({ metric, result }) => ({ + model, + metric: metric.name, + score: result.score, + report: result.naturalLanguageReport, + error: result.encounteredError, + })), ), })), )} @@ -139,9 +133,7 @@ export const improveSystemPrompt = async (params: { ); if (response.status !== "ok") { - throw new Error( - `Failed to get response from LLM: ${JSON.stringify(response)}`, - ); + throw new Error(`Failed to get response from LLM: ${JSON.stringify(response)}`); } const toolCalls = getToolCallsFromLlmAssistantMessage({ @@ -151,16 +143,13 @@ export const improveSystemPrompt = async (params: { const [proposeSystemPromptToolCall] = toolCalls; if (!proposeSystemPromptToolCall) { - throw new Error( - `Expected a tool call for the proposeSystemPrompt tool, but got none.`, - ); + throw new Error(`Expected a tool call for the proposeSystemPrompt tool, but got none.`); } - const { improvedSystemPrompt, reasoning } = - proposeSystemPromptToolCall.input as { - improvedSystemPrompt: string; - reasoning: string; - }; + const { improvedSystemPrompt, reasoning } = proposeSystemPromptToolCall.input as { + improvedSystemPrompt: string; + reasoning: string; + }; logger.debug(`Proposed system prompt: ${improvedSystemPrompt}`); /** diff --git a/apps/hash-ai-worker-ts/src/activities/shared/request-external-input.ts b/apps/hash-ai-worker-ts/src/activities/shared/request-external-input.ts index b242a4a68e0..b22489a384f 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/request-external-input.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/request-external-input.ts @@ -15,9 +15,7 @@ import type { Client as TemporalClient } from "@temporalio/client"; let temporalClient: TemporalClient | undefined; -export const requestExternalInput = async < - Request extends ExternalInputRequestSignal, ->( +export const requestExternalInput = async ( request: Request, ): Promise> => { temporalClient = temporalClient ?? (await createTemporalClient()); diff --git a/apps/hash-ai-worker-ts/src/activities/shared/stringify.ts b/apps/hash-ai-worker-ts/src/activities/shared/stringify.ts index 37a39795a9f..154ffb9ff03 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/stringify.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/stringify.ts @@ -2,7 +2,5 @@ export const stringify = (obj: unknown) => JSON.stringify( obj, undefined, - ["test", "development"].includes(process.env.NODE_ENV ?? "") - ? 2 - : undefined, + ["test", "development"].includes(process.env.NODE_ENV ?? "") ? 2 : undefined, ); diff --git a/apps/hash-ai-worker-ts/src/activities/shared/use-file-system-file-from-url.ts b/apps/hash-ai-worker-ts/src/activities/shared/use-file-system-file-from-url.ts index 506b8757396..c1c2aaf2316 100644 --- a/apps/hash-ai-worker-ts/src/activities/shared/use-file-system-file-from-url.ts +++ b/apps/hash-ai-worker-ts/src/activities/shared/use-file-system-file-from-url.ts @@ -18,16 +18,10 @@ const baseFilePath = path.join(tmpdir(), "hash-tmp-files"); export const useFileSystemPathFromEntity = async ( fileEntity: Pick, "entityId" | "properties">, - callback: ({ - fileSystemPath, - }: { - fileSystemPath: string; - }) => Promise, + callback: ({ fileSystemPath }: { fileSystemPath: string }) => Promise, ): Promise => { const fileUrl = - fileEntity.properties[ - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/" - ]; + fileEntity.properties["https://blockprotocol.org/@blockprotocol/types/property-type/file-url/"]; if (!fileUrl) { throw new Error( @@ -42,9 +36,7 @@ export const useFileSystemPathFromEntity = async ( } const storageKey = - fileEntity.properties[ - "https://hash.ai/@h/types/property-type/file-storage-key/" - ]; + fileEntity.properties["https://hash.ai/@h/types/property-type/file-storage-key/"]; if (!storageKey) { throw new Error( @@ -79,16 +71,12 @@ export const useFileSystemPathFromEntity = async ( try { const fileStream = createWriteStream(filePath); await finished( - Readable.fromWeb( - fetchFileResponse.body as ReadableStream, - ).pipe(fileStream), + Readable.fromWeb(fetchFileResponse.body as ReadableStream).pipe(fileStream), ); } catch (error) { await unlink(filePath).catch(() => {}); - throw new Error( - `Failed to write file to file system: ${(error as Error).message}`, - ); + throw new Error(`Failed to write file to file system: ${(error as Error).message}`); } try { diff --git a/apps/hash-ai-worker-ts/src/instrument.ts b/apps/hash-ai-worker-ts/src/instrument.ts index b3ff0bfb4f8..0f15a117660 100644 --- a/apps/hash-ai-worker-ts/src/instrument.ts +++ b/apps/hash-ai-worker-ts/src/instrument.ts @@ -43,10 +43,7 @@ export const otelSetup: ReturnType = (() => { throw error; } // eslint-disable-next-line no-console - console.error( - "OpenTelemetry bootstrap failed; AI worker will start without telemetry.", - error, - ); + console.error("OpenTelemetry bootstrap failed; AI worker will start without telemetry.", error); return undefined; } })(); diff --git a/apps/hash-ai-worker-ts/src/main.ts b/apps/hash-ai-worker-ts/src/main.ts index 916dd67bdfa..f31e22d68d3 100644 --- a/apps/hash-ai-worker-ts/src/main.ts +++ b/apps/hash-ai-worker-ts/src/main.ts @@ -76,8 +76,7 @@ const workflowSource: WorkflowSource = * to webpack 'alias'. */ new TsconfigPathsPlugin({ - configFile: - "../../libs/@local/tsconfig/legacy-base-tsconfig-to-refactor.json", + configFile: "../../libs/@local/tsconfig/legacy-base-tsconfig-to-refactor.json", }), ], }, diff --git a/apps/hash-ai-worker-ts/src/shared/queries.ts b/apps/hash-ai-worker-ts/src/shared/queries.ts index 4fa84e19586..09c4d4ca53b 100644 --- a/apps/hash-ai-worker-ts/src/shared/queries.ts +++ b/apps/hash-ai-worker-ts/src/shared/queries.ts @@ -19,5 +19,6 @@ export type GetExternalInputResponseQuery = QueryDefinition< "getExternalInputResponse" >; -export const getExternalInputResponseQuery: GetExternalInputResponseQuery = - defineQuery("getExternalInputResponse"); +export const getExternalInputResponseQuery: GetExternalInputResponseQuery = defineQuery( + "getExternalInputResponse", +); diff --git a/apps/hash-ai-worker-ts/src/shared/signals.ts b/apps/hash-ai-worker-ts/src/shared/signals.ts index 9b8ce1e71c0..414a32e58ee 100644 --- a/apps/hash-ai-worker-ts/src/shared/signals.ts +++ b/apps/hash-ai-worker-ts/src/shared/signals.ts @@ -22,9 +22,9 @@ export const logProgressSignal = defineSignal<[ProgressLogSignal]>( /** * Send a request for external input */ -export const externalInputRequestSignal = defineSignal< - [ExternalInputRequestSignal] ->("externalInputRequest" satisfies FlowSignalType); +export const externalInputRequestSignal = defineSignal<[ExternalInputRequestSignal]>( + "externalInputRequest" satisfies FlowSignalType, +); /** * State from which to restore the 'research entities' action, which can be reset to at the user's request. @@ -46,9 +46,9 @@ export type ResearchActionCheckpointSignal = ProgressLogBase & { checkpointId: string; }; -export const researchActionCheckpointSignal = defineSignal< - [ResearchActionCheckpointSignal] ->("researchActionCheckpoint" satisfies FlowSignalType); +export const researchActionCheckpointSignal = defineSignal<[ResearchActionCheckpointSignal]>( + "researchActionCheckpoint" satisfies FlowSignalType, +); /** * Stop a HASH AI worker (not the Temporal worker) diff --git a/apps/hash-ai-worker-ts/src/shared/testing-utilities/get-alice-user-account-id.ts b/apps/hash-ai-worker-ts/src/shared/testing-utilities/get-alice-user-account-id.ts index dede3a4b7b6..a218c9fe137 100644 --- a/apps/hash-ai-worker-ts/src/shared/testing-utilities/get-alice-user-account-id.ts +++ b/apps/hash-ai-worker-ts/src/shared/testing-utilities/get-alice-user-account-id.ts @@ -1,7 +1,4 @@ -import { - extractBaseUrl, - extractWebIdFromEntityId, -} from "@blockprotocol/type-system"; +import { extractBaseUrl, extractWebIdFromEntityId } from "@blockprotocol/type-system"; import { publicUserAccountId } from "@local/hash-backend-utils/public-user-account-id"; import { queryEntities } from "@local/hash-graph-sdk/entity"; import { @@ -26,17 +23,13 @@ export const getAliceUserAccountId = async () => { { filter: { all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.user.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.user.entityTypeId, { + ignoreParents: true, + }), { equal: [ { - path: [ - "properties", - extractBaseUrl(systemPropertyTypes.shortname.propertyTypeId), - ], + path: ["properties", extractBaseUrl(systemPropertyTypes.shortname.propertyTypeId)], }, { parameter: "alice" }, ], @@ -53,9 +46,7 @@ export const getAliceUserAccountId = async () => { throw new Error("Could not find a user entity with shortname 'alice'"); } - const aliceUserAccountId = extractWebIdFromEntityId( - aliceUserEntity.metadata.recordId.entityId, - ); + const aliceUserAccountId = extractWebIdFromEntityId(aliceUserEntity.metadata.recordId.entityId); return aliceUserAccountId as UserId; }; diff --git a/apps/hash-ai-worker-ts/src/shared/testing-utilities/mock-get-flow-context.ts b/apps/hash-ai-worker-ts/src/shared/testing-utilities/mock-get-flow-context.ts index 28491f8ea52..96d23d24efd 100644 --- a/apps/hash-ai-worker-ts/src/shared/testing-utilities/mock-get-flow-context.ts +++ b/apps/hash-ai-worker-ts/src/shared/testing-utilities/mock-get-flow-context.ts @@ -9,11 +9,7 @@ import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-id import { graphApiClient } from "../../activities/shared/graph-api-client.js"; import { getAliceUserAccountId } from "./get-alice-user-account-id.js"; -import type { - ActorEntityUuid, - EntityUuid, - WebId, -} from "@blockprotocol/type-system"; +import type { ActorEntityUuid, EntityUuid, WebId } from "@blockprotocol/type-system"; import type { AiFlowActionDefinitionId } from "@local/hash-isomorphic-utils/flows/action-definitions"; import type { RunAiFlowWorkflowParams } from "@local/hash-isomorphic-utils/flows/temporal-types"; import type { FlowDefinition } from "@local/hash-isomorphic-utils/flows/types"; @@ -84,9 +80,7 @@ vi.mock("@temporalio/activity", async (importOriginal) => { info: { workflowExecution: { workflowId: - dummyFlowEntity.properties[ - "https://hash.ai/@h/types/property-type/workflow-id/" - ], + dummyFlowEntity.properties["https://hash.ai/@h/types/property-type/workflow-id/"], }, activityId: "test-activity-id", }, diff --git a/apps/hash-ai-worker-ts/src/workflows.ts b/apps/hash-ai-worker-ts/src/workflows.ts index 3db30bddf92..179d0558ff0 100644 --- a/apps/hash-ai-worker-ts/src/workflows.ts +++ b/apps/hash-ai-worker-ts/src/workflows.ts @@ -13,10 +13,7 @@ import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-id import { runFlowWorkflow } from "./workflows/run-flow-workflow.js"; -import type { - createAiActivities, - createGraphActivities, -} from "./activities.js"; +import type { createAiActivities, createGraphActivities } from "./activities.js"; import type { ActorEntityUuid, BaseUrl, @@ -42,9 +39,7 @@ const aiActivities = proxyActivities>({ }, }); -const graphActivities = proxyActivities< - ReturnType ->({ +const graphActivities = proxyActivities>({ startToCloseTimeout: "20 second", retry: { maximumAttempts: 3, @@ -108,17 +103,15 @@ export const updateDataTypeEmbeddings = async ( } for (const dataType of dataTypes) { - const generatedEmbeddings = - await aiActivities.createDataTypeEmbeddingsActivity({ - dataType, - }); + const generatedEmbeddings = await aiActivities.createDataTypeEmbeddingsActivity({ + dataType, + }); await graphActivities.updateDataTypeEmbeddings({ authentication: params.authentication, embedding: generatedEmbeddings.embedding, dataTypeId: dataType.schema.$id, - updatedAtTransactionTime: - dataType.metadata.temporalVersioning.transactionTime.start.limit, + updatedAtTransactionTime: dataType.metadata.temporalVersioning.transactionTime.start.limit, reset: true, }); @@ -180,10 +173,9 @@ export const updatePropertyTypeEmbeddings = async ( } for (const propertyType of propertyTypes) { - const generatedEmbeddings = - await aiActivities.createPropertyTypeEmbeddingsActivity({ - propertyType, - }); + const generatedEmbeddings = await aiActivities.createPropertyTypeEmbeddingsActivity({ + propertyType, + }); await graphActivities.updatePropertyTypeEmbeddings({ authentication: params.authentication, @@ -252,17 +244,15 @@ export const updateEntityTypeEmbeddings = async ( } for (const entityType of entityTypes) { - const generatedEmbeddings = - await aiActivities.createEntityTypeEmbeddingsActivity({ - entityType, - }); + const generatedEmbeddings = await aiActivities.createEntityTypeEmbeddingsActivity({ + entityType, + }); await graphActivities.updateEntityTypeEmbeddings({ authentication: params.authentication, entityTypeId: entityType.schema.$id, embedding: generatedEmbeddings.embedding, - updatedAtTransactionTime: - entityType.metadata.temporalVersioning.transactionTime.start.limit, + updatedAtTransactionTime: entityType.metadata.temporalVersioning.transactionTime.start.limit, reset: true, }); @@ -313,12 +303,11 @@ export const updateEntityEmbeddings = async ( } // Activity handles everything: fetch, filter FlowRun/empty, create embeddings, store - const embeddingUsage = - await aiActivities.createAndStoreEntityEmbeddingsActivity({ - authentication: params.authentication, - entityIds: params.entityIds, - embeddingExclusions: params.embeddingExclusions, - }); + const embeddingUsage = await aiActivities.createAndStoreEntityEmbeddingsActivity({ + authentication: params.authentication, + entityIds: params.entityIds, + embeddingExclusions: params.embeddingExclusions, + }); usage.prompt_tokens += embeddingUsage.prompt_tokens; usage.total_tokens += embeddingUsage.total_tokens; @@ -378,17 +367,14 @@ export const updateEntityEmbeddings = async ( } // Extract entity IDs and pass batch to the activity - const entityIds = entities.map( - (entity) => entity.metadata.recordId.entityId, - ); + const entityIds = entities.map((entity) => entity.metadata.recordId.entityId); // Activity handles: fetch, create embeddings, store - const embeddingUsage = - await aiActivities.createAndStoreEntityEmbeddingsActivity({ - authentication: params.authentication, - entityIds, - embeddingExclusions: params.embeddingExclusions, - }); + const embeddingUsage = await aiActivities.createAndStoreEntityEmbeddingsActivity({ + authentication: params.authentication, + entityIds, + embeddingExclusions: params.embeddingExclusions, + }); usage.prompt_tokens += embeddingUsage.prompt_tokens; usage.total_tokens += embeddingUsage.total_tokens; @@ -473,11 +459,10 @@ export const updateAllEntityEmbeddings = async ( // Process batches of webs, paginating through system machines // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- cursor is reassigned in the loop while (true) { - const { machineIds, cursor: nextCursor } = - await graphActivities.getSystemMachineIds({ - cursor: machineCursor, - limit: WEBS_PER_BATCH, - }); + const { machineIds, cursor: nextCursor } = await graphActivities.getSystemMachineIds({ + cursor: machineCursor, + limit: WEBS_PER_BATCH, + }); if (machineIds.length === 0) { break; @@ -526,9 +511,7 @@ export const updateAllEntityEmbeddings = async ( return usage; }; -export const parseTextFromFile = async ( - params: ParseTextFromFileParams, -): Promise => { +export const parseTextFromFile = async (params: ParseTextFromFileParams): Promise => { await aiActivities.parseTextFromFileActivity(params); }; diff --git a/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow.ts b/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow.ts index 59de60509c5..4a714543c97 100644 --- a/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow.ts +++ b/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow.ts @@ -1,7 +1,4 @@ -import { - ActivityCancellationType, - proxyActivities, -} from "@temporalio/workflow"; +import { ActivityCancellationType, proxyActivities } from "@temporalio/workflow"; import { processFlowWorkflow } from "@local/hash-backend-utils/flows/process-flow-workflow"; import { type AiFlowActionDefinitionId } from "@local/hash-isomorphic-utils/flows/action-definitions"; @@ -15,10 +12,7 @@ import type { RunAiFlowWorkflowParams, RunFlowWorkflowResponse, } from "@local/hash-isomorphic-utils/flows/temporal-types"; -import type { - FlowDefinition, - FlowTrigger, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { FlowDefinition, FlowTrigger } from "@local/hash-isomorphic-utils/flows/types"; type FlowActivityId = keyof ReturnType; @@ -29,9 +23,7 @@ type FlowActivityId = keyof ReturnType; * - [ideally] the activity has checks for cancellation at appropriate points in its execution and bails out of work * - [ideally] the activity includes state with its heartbeat and checks the lastHeartbeatDetails to resume from previous state */ -const activitiesHandlingCancellation: FlowActivityId[] = [ - "researchEntitiesAction", -]; +const activitiesHandlingCancellation: FlowActivityId[] = ["researchEntitiesAction"]; const activitiesHeartbeating: FlowActivityId[] = [ ...activitiesHandlingCancellation, @@ -44,9 +36,7 @@ const proxyFlowActivity: ProxyFlowActivity< > = (params) => { const { actionName, maximumAttempts, activityId } = params; - const { [actionName]: action } = proxyActivities< - ReturnType - >({ + const { [actionName]: action } = proxyActivities>({ cancellationType: activitiesHandlingCancellation.includes(actionName) ? ActivityCancellationType.WAIT_CANCELLATION_COMPLETED : ActivityCancellationType.ABANDON, diff --git a/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow/set-query-and-signal-handlers.ts b/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow/set-query-and-signal-handlers.ts index f6c959ed57f..ed5b4ed8d3d 100644 --- a/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow/set-query-and-signal-handlers.ts +++ b/apps/hash-ai-worker-ts/src/workflows/run-flow-workflow/set-query-and-signal-handlers.ts @@ -32,46 +32,40 @@ export const setQueryAndSignalHandlers = () => { } >(); - setHandler( - externalInputRequestSignal, - (request: ExternalInputRequestSignal) => { - if (!externalInputRequestsById.has(request.requestId)) { - externalInputRequestsById.set(request.requestId, { request }); - } - }, - ); + setHandler(externalInputRequestSignal, (request: ExternalInputRequestSignal) => { + if (!externalInputRequestsById.has(request.requestId)) { + externalInputRequestsById.set(request.requestId, { request }); + } + }); - setHandler( - externalInputResponseSignal, - (response: ExternalInputResponseSignal) => { - const { requestId } = response; - const inputRequestRecord = externalInputRequestsById.get(requestId); + setHandler(externalInputResponseSignal, (response: ExternalInputResponseSignal) => { + const { requestId } = response; + const inputRequestRecord = externalInputRequestsById.get(requestId); - if (!inputRequestRecord) { - /** - * It's not clear in what circumstances this will happen, and we can't do much about it, - * but we should log it to be aware if it is happening. - */ - sinks.sentry.captureException( - new Error( - `Received response for external input request ${requestId}, but no record of request was found`, - ), - ); - return; - } + if (!inputRequestRecord) { + /** + * It's not clear in what circumstances this will happen, and we can't do much about it, + * but we should log it to be aware if it is happening. + */ + sinks.sentry.captureException( + new Error( + `Received response for external input request ${requestId}, but no record of request was found`, + ), + ); + return; + } - if (response.type !== inputRequestRecord.request.type) { - sinks.sentry.captureException( - new Error( - `Response for external input request ${requestId} has type ${response.type}, but expected ${inputRequestRecord.request.type}`, - ), - ); - return; - } + if (response.type !== inputRequestRecord.request.type) { + sinks.sentry.captureException( + new Error( + `Response for external input request ${requestId} has type ${response.type}, but expected ${inputRequestRecord.request.type}`, + ), + ); + return; + } - inputRequestRecord.response = response; - }, - ); + inputRequestRecord.response = response; + }); setHandler(getExternalInputResponseQuery, ({ requestId }) => { const inputRequestRecord = externalInputRequestsById.get(requestId); diff --git a/apps/hash-ai-worker-ts/vitest.config.ts b/apps/hash-ai-worker-ts/vitest.config.ts index 7ac352a7477..506591a6451 100644 --- a/apps/hash-ai-worker-ts/vitest.config.ts +++ b/apps/hash-ai-worker-ts/vitest.config.ts @@ -8,10 +8,7 @@ import { monorepoRootDir } from "@local/hash-backend-utils/environment"; export default defineConfig(({ mode }) => { return { test: { - env: - process.env.TEST_AI === "true" - ? loadEnv(mode, monorepoRootDir, "") - : undefined, + env: process.env.TEST_AI === "true" ? loadEnv(mode, monorepoRootDir, "") : undefined, coverage: { enabled: process.env.TEST_COVERAGE === "true", provider: "istanbul", diff --git a/apps/hash-api/codegen.config.ts b/apps/hash-api/codegen.config.ts index 89c9111c92d..11524bc187c 100644 --- a/apps/hash-api/codegen.config.ts +++ b/apps/hash-api/codegen.config.ts @@ -4,8 +4,7 @@ import type { CodegenConfig } from "@graphql-codegen/cli"; const config: CodegenConfig = { overwrite: true, - schema: - "../../libs/@local/hash-isomorphic-utils/src/graphql/type-defs/**/*.ts", + schema: "../../libs/@local/hash-isomorphic-utils/src/graphql/type-defs/**/*.ts", generates: { "./src/graphql/graphql-schema.gen.json": { plugins: ["introspection"], @@ -15,9 +14,7 @@ const config: CodegenConfig = { }, "./src/graphql/api-types.gen.ts": { plugins: ["typescript", "typescript-resolvers", "typescript-operations"], - documents: [ - "../../libs/@local/hash-isomorphic-utils/src/graphql/queries/**/*.ts", - ], + documents: ["../../libs/@local/hash-isomorphic-utils/src/graphql/queries/**/*.ts"], hooks: { afterOneFileWrite: ["oxfmt --write --ignore-path /dev/null"], }, diff --git a/apps/hash-api/eslint.config.js b/apps/hash-api/eslint.config.js index 6e92a15b2c5..99c209d4033 100644 --- a/apps/hash-api/eslint.config.js +++ b/apps/hash-api/eslint.config.js @@ -1,8 +1,4 @@ -import { - createBase, - defineConfig, - disableRules, -} from "@local/eslint/deprecated"; +import { createBase, defineConfig, disableRules } from "@local/eslint/deprecated"; export default defineConfig([ { diff --git a/apps/hash-api/public/consent.js b/apps/hash-api/public/consent.js index f86269d93ed..a85d959630e 100644 --- a/apps/hash-api/public/consent.js +++ b/apps/hash-api/public/consent.js @@ -1,7 +1,5 @@ function submitConsentForm(submitValue) { - var grantScope = document.querySelectorAll( - 'input[name="grant_scope"]:checked', - ); + var grantScope = document.querySelectorAll('input[name="grant_scope"]:checked'); var grantScopeValues = []; for (var i = 0; i < grantScope.length; i++) { grantScopeValues.push(grantScope[i].value); diff --git a/apps/hash-api/src/ai/gpt/generate-hashgpt-schema.ts b/apps/hash-api/src/ai/gpt/generate-hashgpt-schema.ts index 65be5968f79..cc6cdfc9662 100644 --- a/apps/hash-api/src/ai/gpt/generate-hashgpt-schema.ts +++ b/apps/hash-api/src/ai/gpt/generate-hashgpt-schema.ts @@ -17,39 +17,34 @@ const config = { tsconfig: path.resolve(__dirname, "../../../tsconfig.json"), }; -const { $ref: queryEntitiesRequestRef, definitions: queryEntitiesRequestDefs } = - generator.createGenerator(config).createSchema("GptQueryEntitiesRequestBody"); +const { $ref: queryEntitiesRequestRef, definitions: queryEntitiesRequestDefs } = generator + .createGenerator(config) + .createSchema("GptQueryEntitiesRequestBody"); -const { - $ref: queryEntitiesResponseRef, - definitions: queryEntitiesResponseDefs, -} = generator +const { $ref: queryEntitiesResponseRef, definitions: queryEntitiesResponseDefs } = generator .createGenerator(config) .createSchema("GptQueryEntitiesResponseBody"); -const { $ref: queryTypesRequestRef, definitions: queryTypesRequestDefs } = - generator - .createGenerator({ - ...config, - path: path.resolve(__dirname, "gpt-query-types.ts"), - }) - .createSchema("GptQueryTypesRequestBody"); +const { $ref: queryTypesRequestRef, definitions: queryTypesRequestDefs } = generator + .createGenerator({ + ...config, + path: path.resolve(__dirname, "gpt-query-types.ts"), + }) + .createSchema("GptQueryTypesRequestBody"); -const { $ref: queryTypesResponseRef, definitions: queryTypesResponseDefs } = - generator - .createGenerator({ - ...config, - path: path.resolve(__dirname, "gpt-query-types.ts"), - }) - .createSchema("GptQueryTypesResponseBody"); +const { $ref: queryTypesResponseRef, definitions: queryTypesResponseDefs } = generator + .createGenerator({ + ...config, + path: path.resolve(__dirname, "gpt-query-types.ts"), + }) + .createSchema("GptQueryTypesResponseBody"); -const { $ref: getUserWebsResponseRef, definitions: getUserWebsResponseDefs } = - generator - .createGenerator({ - ...config, - path: path.resolve(__dirname, "gpt-get-user-webs.ts"), - }) - .createSchema("GptGetUserWebsResponseBody"); +const { $ref: getUserWebsResponseRef, definitions: getUserWebsResponseDefs } = generator + .createGenerator({ + ...config, + path: path.resolve(__dirname, "gpt-get-user-webs.ts"), + }) + .createSchema("GptGetUserWebsResponseBody"); const components = { schemas: { @@ -154,7 +149,4 @@ const rewrittenSchema = JSON.stringify(openApiSchema, null, 2).replaceAll( "#/components/schemas/", ); -writeFileSync( - path.resolve(__dirname, "openapi-schema.gen.json"), - rewrittenSchema, -); +writeFileSync(path.resolve(__dirname, "openapi-schema.gen.json"), rewrittenSchema); diff --git a/apps/hash-api/src/ai/gpt/gpt-get-user-webs.ts b/apps/hash-api/src/ai/gpt/gpt-get-user-webs.ts index 257b5b8e2a1..9cb014066a2 100644 --- a/apps/hash-api/src/ai/gpt/gpt-get-user-webs.ts +++ b/apps/hash-api/src/ai/gpt/gpt-get-user-webs.ts @@ -25,11 +25,7 @@ export const gptGetUserWebs: RequestHandler< return; } - const userWebs = await getUserSimpleWebs( - req.context, - { actorId: user.accountId }, - { user }, - ); + const userWebs = await getUserSimpleWebs(req.context, { actorId: user.accountId }, { user }); res.status(200).json({ userWebs }); }; diff --git a/apps/hash-api/src/ai/gpt/gpt-query-entities.ts b/apps/hash-api/src/ai/gpt/gpt-query-entities.ts index 372dee62147..79009a8b19c 100644 --- a/apps/hash-api/src/ai/gpt/gpt-query-entities.ts +++ b/apps/hash-api/src/ai/gpt/gpt-query-entities.ts @@ -136,24 +136,24 @@ export const gptQueryEntities: RequestHandler< return; } - const { types, query, entityIds, webUuids, traversalDepth, includeDrafts } = - req.body; + const { types, query, entityIds, webUuids, traversalDepth, includeDrafts } = req.body; const depth = traversalDepth ?? 2; const semanticSearchString = query ? await req.context.temporalClient.workflow - .execute< - (params: CreateEmbeddingsParams) => Promise - >("createEmbeddings", { - taskQueue: "ai", - args: [ - { - input: [query], - }, - ], - workflowId: generateUuid(), - }) + .execute<(params: CreateEmbeddingsParams) => Promise>( + "createEmbeddings", + { + taskQueue: "ai", + args: [ + { + input: [query], + }, + ], + workflowId: generateUuid(), + }, + ) .then(({ embeddings }) => embeddings[0]) : null; @@ -172,8 +172,7 @@ export const gptQueryEntities: RequestHandler< path: [ "type", // Sometimes the GPT sends the type's id instead of a title - type.startsWith("http://") || - type.startsWith("https://") + type.startsWith("http://") || type.startsWith("https://") ? "versionedUrl" : "title", ], @@ -191,9 +190,7 @@ export const gptQueryEntities: RequestHandler< equal: [ { path: ["uuid"] }, { - parameter: extractEntityUuidFromEntityId( - entityId as EntityId, - ), + parameter: extractEntityUuidFromEntityId(entityId as EntityId), }, ], })), @@ -259,12 +256,9 @@ export const gptQueryEntities: RequestHandler< { user }, ); - const { entities: entitiesWithoutHrefs, entityTypes } = - getSimpleGraph(subgraph); + const { entities: entitiesWithoutHrefs, entityTypes } = getSimpleGraph(subgraph); - const resolveEntityWeb = async (simpleEntity: { - entityId: EntityId; - }): Promise => { + const resolveEntityWeb = async (simpleEntity: { entityId: EntityId }): Promise => { /** * Resolve details of the web that the entity belongs to */ @@ -277,21 +271,17 @@ export const gptQueryEntities: RequestHandler< req.context, { actorId: user.accountId }, { - entityId: entityIdFromComponents( - webWebId, - webWebId as string as EntityUuid, - ), + entityId: entityIdFromComponents(webWebId, webWebId as string as EntityUuid), }, ); - const isUser = - owningEntity.metadata.entityTypeIds[0].includes("/user/"); + const isUser = owningEntity.metadata.entityTypeIds[0].includes("/user/"); web = { type: isUser ? "User" : "Organization", - name: ( - owningEntity.properties as UserProperties | OrganizationProperties - )["https://hash.ai/@h/types/property-type/shortname/"]!, + name: (owningEntity.properties as UserProperties | OrganizationProperties)[ + "https://hash.ai/@h/types/property-type/shortname/" + ]!, uuid: webWebId, }; diff --git a/apps/hash-api/src/ai/gpt/gpt-query-types.ts b/apps/hash-api/src/ai/gpt/gpt-query-types.ts index ef9b8e5e6c7..39f8b33299b 100644 --- a/apps/hash-api/src/ai/gpt/gpt-query-types.ts +++ b/apps/hash-api/src/ai/gpt/gpt-query-types.ts @@ -61,84 +61,80 @@ export const gptQueryTypes: RequestHandler< const semanticSearchString = query ? await req.context.temporalClient.workflow - .execute< - (params: CreateEmbeddingsParams) => Promise - >("createEmbeddings", { - taskQueue: "ai", - args: [ - { - input: [query], - }, - ], - workflowId: generateUuid(), - }) + .execute<(params: CreateEmbeddingsParams) => Promise>( + "createEmbeddings", + { + taskQueue: "ai", + args: [ + { + input: [query], + }, + ], + workflowId: generateUuid(), + }, + ) .then(({ embeddings }) => embeddings[0]) : null; - const queryResponse: GptQueryTypesResponseBody = - await queryEntityTypeSubgraph( - req.context.graphApi, - { actorId: user.accountId }, - { - filter: { - all: [ - ...(webUuids?.length - ? [ - { - any: webUuids.map((webUuid) => ({ - equal: [{ path: ["webId"] }, { parameter: webUuid }], - })), - }, - ] - : []), - ...(semanticSearchString - ? [ - { - cosineDistance: [ - { path: ["embedding"] }, - { parameter: semanticSearchString }, - { parameter: 0.9 }, - ], - }, - ] - : []), - ], - }, - temporalAxes: currentTimeInstantTemporalAxes, - graphResolveDepths: { - ...almostFullOntologyResolveDepths, - constrainsLinkDestinationsOn: 4, - constrainsLinksOn: 4, - }, - traversalPaths: [], + const queryResponse: GptQueryTypesResponseBody = await queryEntityTypeSubgraph( + req.context.graphApi, + { actorId: user.accountId }, + { + filter: { + all: [ + ...(webUuids?.length + ? [ + { + any: webUuids.map((webUuid) => ({ + equal: [{ path: ["webId"] }, { parameter: webUuid }], + })), + }, + ] + : []), + ...(semanticSearchString + ? [ + { + cosineDistance: [ + { path: ["embedding"] }, + { parameter: semanticSearchString }, + { parameter: 0.9 }, + ], + }, + ] + : []), + ], }, - ).then(async ({ subgraph }) => { - const entityTypes: SimpleEntityType[] = []; + temporalAxes: currentTimeInstantTemporalAxes, + graphResolveDepths: { + ...almostFullOntologyResolveDepths, + constrainsLinkDestinationsOn: 4, + constrainsLinksOn: 4, + }, + traversalPaths: [], + }, + ).then(async ({ subgraph }) => { + const entityTypes: SimpleEntityType[] = []; - const vertices = typedValues(subgraph.vertices).flatMap((vertex) => - typedValues(vertex), - ); + const vertices = typedValues(subgraph.vertices).flatMap((vertex) => typedValues(vertex)); - for (const vertex of vertices) { - if (vertex.kind === "entityType") { - const entityType = entityTypes.find( - (type) => type.entityTypeId === vertex.inner.schema.$id, - ); + for (const vertex of vertices) { + if (vertex.kind === "entityType") { + const entityType = entityTypes.find( + (type) => type.entityTypeId === vertex.inner.schema.$id, + ); - if (!entityType) { - entityTypes.push( - getSimpleEntityType(subgraph, vertex.inner.schema.$id), - ); - } + if (!entityType) { + entityTypes.push(getSimpleEntityType(subgraph, vertex.inner.schema.$id)); } } + } - return { - entityTypes: ` + return { + entityTypes: ` ---- Entity Types ---- ${stringifyResults(entityTypes)}`, - }; - }); + }; + }); res.status(200).json(queryResponse); }; diff --git a/apps/hash-api/src/ai/gpt/upsert-gpt-oauth-client.ts b/apps/hash-api/src/ai/gpt/upsert-gpt-oauth-client.ts index b3ebc3adf86..7363f00a253 100644 --- a/apps/hash-api/src/ai/gpt/upsert-gpt-oauth-client.ts +++ b/apps/hash-api/src/ai/gpt/upsert-gpt-oauth-client.ts @@ -52,18 +52,14 @@ export const upsertGptOauthClient: RequestHandler< } if (!redirectUri) { - res - .status(400) - .send({ error: "redirectUri is required in the request body" }); + res.status(400).send({ error: "redirectUri is required in the request body" }); return; } const parsedUrl = new URL(redirectUri); if (parsedUrl.hostname !== "chat.openai.com") { - res - .status(400) - .send({ error: "redirectUri must be a valid ChatGPT redirect URI" }); + res.status(400).send({ error: "redirectUri must be a valid ChatGPT redirect URI" }); return; } @@ -72,9 +68,7 @@ export const upsertGptOauthClient: RequestHandler< }); if (existingClients.length > 1) { - res - .status(500) - .send({ error: `Multiple clients with the name ${clientName} exist` }); + res.status(500).send({ error: `Multiple clients with the name ${clientName} exist` }); } else if (existingClients.length === 0) { const { data: newClient } = await hydraAdmin.createOAuth2Client({ oAuth2Client: { diff --git a/apps/hash-api/src/ai/infer-entities-websocket.ts b/apps/hash-api/src/ai/infer-entities-websocket.ts index 688469ad700..6091c0905ef 100644 --- a/apps/hash-api/src/ai/infer-entities-websocket.ts +++ b/apps/hash-api/src/ai/infer-entities-websocket.ts @@ -1,9 +1,6 @@ import { WebSocketServer } from "ws"; -import { - getFlowRunEntityById, - getFlowRuns, -} from "@local/hash-backend-utils/flows"; +import { getFlowRunEntityById, getFlowRuns } from "@local/hash-backend-utils/flows"; import { externalInputResponseSignal } from "@local/hash-isomorphic-utils/flows/signals"; import { getUserAndSession } from "../auth/create-auth-handlers"; @@ -103,10 +100,10 @@ const inferEntitiesMessageHandler = async ({ } const handle = temporalClient.workflow.getHandle(workflowId); - await handle.signal<[ExternalInputResponseSignal]>( - externalInputResponseSignal, - { ...payload, resolvedBy: user.accountId }, - ); + await handle.signal<[ExternalInputResponseSignal]>(externalInputResponseSignal, { + ...payload, + resolvedBy: user.accountId, + }); return; } } diff --git a/apps/hash-api/src/ai/infer-entities-websocket/handle-infer-entities-request.ts b/apps/hash-api/src/ai/infer-entities-websocket/handle-infer-entities-request.ts index 94fbd8d28f8..992e57f67dc 100644 --- a/apps/hash-api/src/ai/infer-entities-websocket/handle-infer-entities-request.ts +++ b/apps/hash-api/src/ai/infer-entities-websocket/handle-infer-entities-request.ts @@ -23,10 +23,7 @@ import type { RunFlowWorkflowParams, RunFlowWorkflowResponse, } from "@local/hash-isomorphic-utils/flows/temporal-types"; -import type { - FlowTrigger, - StepOutput, -} from "@local/hash-isomorphic-utils/flows/types"; +import type { FlowTrigger, StepOutput } from "@local/hash-isomorphic-utils/flows/types"; import type { Client } from "@temporalio/client"; export const handleInferEntitiesRequest = async ({ @@ -40,8 +37,7 @@ export const handleInferEntitiesRequest = async ({ storageProvider: FileStorageProvider; temporalClient: Client; message: DistributiveOmit< - | ManualInferenceWebsocketRequestMessage - | AutomaticInferenceWebsocketRequestMessage, + ManualInferenceWebsocketRequestMessage | AutomaticInferenceWebsocketRequestMessage, "cookie" >; user: User; @@ -89,8 +85,7 @@ export const handleInferEntitiesRequest = async ({ (triggerOutput) => triggerOutput.outputName === ("visitedWebPage" satisfies AutomaticInferenceTriggerInputName) && - triggerOutput.payload.value.url === - triggerOutputs.visitedWebPage.value.url, + triggerOutput.payload.value.url === triggerOutputs.visitedWebPage.value.url, ); if (flowIsAlreadyRunningOnPage) { diff --git a/apps/hash-api/src/auth/create-auth-handlers.ts b/apps/hash-api/src/auth/create-auth-handlers.ts index ae8b2990606..6adc5929fb7 100644 --- a/apps/hash-api/src/auth/create-auth-handlers.ts +++ b/apps/hash-api/src/auth/create-auth-handlers.ts @@ -27,11 +27,7 @@ const kratosAfterRegistrationHookHandler = ( context: ImpureGraphContext, logger: Logger, - ): RequestHandler< - Record, - string, - { identity: KratosUserIdentity } - > => + ): RequestHandler, string, { identity: KratosUserIdentity }> => (req, res) => { const { body: { @@ -43,15 +39,11 @@ const kratosAfterRegistrationHookHandler = // Authenticate the request originates from the kratos server if (!requestHeaderContainsValidKratosApiKey(req)) { logger.error("Kratos webhook called with invalid API key"); - Sentry.captureException( - new Error("Kratos webhook called with invalid API key"), - ); + Sentry.captureException(new Error("Kratos webhook called with invalid API key")); res .status(401) - .send( - 'Please provide the kratos API key using a "KRATOS_API_KEY" request header', - ) + .send('Please provide the kratos API key using a "KRATOS_API_KEY" request header') .end(); return; @@ -105,10 +97,7 @@ export const addKratosAfterRegistrationHandler = ({ context: ImpureGraphContext; logger: Logger; }) => { - app.post( - "/kratos-after-registration", - kratosAfterRegistrationHookHandler(context, logger), - ); + app.post("/kratos-after-registration", kratosAfterRegistrationHookHandler(context, logger)); }; export const getUserAndSession = async ({ @@ -136,9 +125,7 @@ export const getUserAndSession = async ({ .then(({ data }) => data) .catch((err: AxiosError) => { if (err.response && err.response.status === 403) { - logger.debug( - "Session requires AAL2 but only has AAL1. Treating as unauthenticated.", - ); + logger.debug("Session requires AAL2 but only has AAL1. Treating as unauthenticated."); return undefined; } logger.debug( @@ -161,9 +148,8 @@ export const getUserAndSession = async ({ const primaryEmailAddress = traits.emails[0]; const primaryEmailVerified = - identity.verifiable_addresses?.find( - ({ value }) => value === primaryEmailAddress, - )?.verified === true; + identity.verifiable_addresses?.find(({ value }) => value === primaryEmailAddress) + ?.verified === true; let user = await getUser(context, authentication, { kratosIdentityId, @@ -226,9 +212,7 @@ export const createAuthMiddleware = (params: { }, ); if (user) { - req.primaryEmailVerified = await isUserEmailVerified( - user.kratosIdentityId, - ); + req.primaryEmailVerified = await isUserEmailVerified(user.kratosIdentityId); req.user = user; next(); return; diff --git a/apps/hash-api/src/auth/create-unverified-email-cleanup-job.ts b/apps/hash-api/src/auth/create-unverified-email-cleanup-job.ts index 9795b714773..bc735ca2572 100644 --- a/apps/hash-api/src/auth/create-unverified-email-cleanup-job.ts +++ b/apps/hash-api/src/auth/create-unverified-email-cleanup-job.ts @@ -34,9 +34,7 @@ const parsePositiveIntegerEnv = ( const parsedValue = Number.parseInt(rawValue, 10); if (Number.isNaN(parsedValue) || parsedValue <= 0) { - throw new Error( - `${envVarName} must be a positive integer, got "${rawValue}"`, - ); + throw new Error(`${envVarName} must be a positive integer, got "${rawValue}"`); } return parsedValue; @@ -80,9 +78,8 @@ const isPrimaryEmailVerified = (identity: Identity): boolean => { } return ( - identity.verifiable_addresses?.find( - ({ value }) => value === primaryEmailAddress, - )?.verified === true + identity.verifiable_addresses?.find(({ value }) => value === primaryEmailAddress)?.verified === + true ); }; @@ -93,9 +90,7 @@ export const createUnverifiedEmailCleanupJob = ({ context: ImpureGraphContext; logger: Logger; }) => { - const rolloutAt = parseRolloutDate( - process.env.HASH_EMAIL_VERIFICATION_ROLLOUT_AT, - ); + const rolloutAt = parseRolloutDate(process.env.HASH_EMAIL_VERIFICATION_ROLLOUT_AT); const releaseTtlHours = parsePositiveIntegerEnv( process.env.HASH_EMAIL_VERIFICATION_RELEASE_TTL_HOURS, @@ -116,28 +111,21 @@ export const createUnverifiedEmailCleanupJob = ({ const now = Date.now(); const authentication = { actorId: systemAccountId }; - const { entities: userEntities } = await queryEntities( - context, - authentication, - { - filter: { - all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.user.entityTypeId, - { - ignoreParents: true, - }, - ), - { - equal: [{ path: ["archived"] }, { parameter: false }], - }, - ], - }, - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts: false, - includePermissions: false, + const { entities: userEntities } = await queryEntities(context, authentication, { + filter: { + all: [ + generateVersionedUrlMatchingFilter(systemEntityTypes.user.entityTypeId, { + ignoreParents: true, + }), + { + equal: [{ path: ["archived"] }, { parameter: false }], + }, + ], }, - ); + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts: false, + includePermissions: false, + }); let releasedEmailCount = 0; @@ -174,11 +162,7 @@ export const createUnverifiedEmailCleanupJob = ({ continue; } - await user.entity.archive( - context.graphApi, - authentication, - context.provenance, - ); + await user.entity.archive(context.graphApi, authentication, context.provenance); await deleteKratosIdentity({ kratosIdentityId: user.kratosIdentityId, }); diff --git a/apps/hash-api/src/auth/oauth-consent-handlers.ts b/apps/hash-api/src/auth/oauth-consent-handlers.ts index 115ac2f767a..f1969632ff8 100644 --- a/apps/hash-api/src/auth/oauth-consent-handlers.ts +++ b/apps/hash-api/src/auth/oauth-consent-handlers.ts @@ -12,10 +12,7 @@ const CSRF_COOKIE_NAME = "_csrf_consent"; /** * Parse a single cookie value from a raw Cookie header string. */ -function parseCookieValue( - cookieHeader: string | undefined, - name: string, -): string | undefined { +function parseCookieValue(cookieHeader: string | undefined, name: string): string | undefined { if (!cookieHeader) { return undefined; } @@ -73,9 +70,7 @@ export const oauthConsentRequestHandler: RequestHandler< // The challenge is used to fetch information about the consent request from ORY hydraAdmin. const consentChallenge = query.consent_challenge; if (!consentChallenge) { - next( - new Error("Expected a consent_challenge to be set but received none."), - ); + next(new Error("Expected a consent_challenge to be set but received none.")); return; } @@ -92,8 +87,7 @@ export const oauthConsentRequestHandler: RequestHandler< grant_scope: consentRequest.requested_scope, // Hydra checks if requested audiences are allowed by the client, so we can simply echo this. - grant_access_token_audience: - consentRequest.requested_access_token_audience, + grant_access_token_audience: consentRequest.requested_access_token_audience, }, }) .then(({ data: redirectTo }) => { @@ -107,9 +101,7 @@ export const oauthConsentRequestHandler: RequestHandler< } if (consentRequest.subject !== req.user.kratosIdentityId) { - res - .status(403) - .send("Consent request subject does not match request user."); + res.status(403).send("Consent request subject does not match request user."); return; } @@ -130,11 +122,7 @@ export const oauthConsentRequestHandler: RequestHandler< // The consent request has now either been accepted automatically or rendered. }; -export const oauthConsentSubmissionHandler: RequestHandler = ( - req, - res, - next, -) => { +export const oauthConsentSubmissionHandler: RequestHandler = (req, res, next) => { if (!req.user) { res.status(401).send("Authentication required to grant consent."); return; @@ -142,10 +130,7 @@ export const oauthConsentSubmissionHandler: RequestHandler = ( // Validate CSRF token (double-submit cookie pattern) const csrfTokenFromBody: unknown = req.body.csrfToken; - const csrfTokenFromCookie = parseCookieValue( - req.headers.cookie, - CSRF_COOKIE_NAME, - ); + const csrfTokenFromCookie = parseCookieValue(req.headers.cookie, CSRF_COOKIE_NAME); if ( typeof csrfTokenFromBody !== "string" || @@ -187,9 +172,7 @@ export const oauthConsentSubmissionHandler: RequestHandler = ( .then(({ data: body }) => { // Verify the consent request subject matches the authenticated user if (body.subject !== req.user?.kratosIdentityId) { - res - .status(403) - .send("Consent request subject does not match authenticated user."); + res.status(403).send("Consent request subject does not match authenticated user."); return; } diff --git a/apps/hash-api/src/auth/ory-kratos.ts b/apps/hash-api/src/auth/ory-kratos.ts index 78a25a15281..1f43ea16b36 100644 --- a/apps/hash-api/src/auth/ory-kratos.ts +++ b/apps/hash-api/src/auth/ory-kratos.ts @@ -7,15 +7,11 @@ import type { CreateIdentityBody, Identity } from "@ory/kratos-client"; export const kratosPublicUrl = getRequiredEnv("HASH_KRATOS_PUBLIC_URL"); -export const kratosFrontendApi = new FrontendApi( - new Configuration({ basePath: kratosPublicUrl }), -); +export const kratosFrontendApi = new FrontendApi(new Configuration({ basePath: kratosPublicUrl })); const adminUrl = getRequiredEnv("HASH_KRATOS_ADMIN_URL"); -export const kratosIdentityApi = new IdentityApi( - new Configuration({ basePath: adminUrl }), -); +export const kratosIdentityApi = new IdentityApi(new Configuration({ basePath: adminUrl })); export type KratosUserIdentityTraits = { shortname?: string; @@ -52,15 +48,13 @@ export const createKratosIdentity = async ( }; if (verifyEmails) { - createIdentityBody.verifiable_addresses = params.traits.emails.map( - (email) => ({ - value: email, - verified: true, - verified_at: new Date().toISOString(), - via: "email" as const, - status: "completed", - }), - ); + createIdentityBody.verifiable_addresses = params.traits.emails.map((email) => ({ + value: email, + verified: true, + verified_at: new Date().toISOString(), + via: "email" as const, + status: "completed", + })); } const { data: kratosUserIdentity } = await kratosIdentityApi.createIdentity({ @@ -70,17 +64,13 @@ export const createKratosIdentity = async ( return kratosUserIdentity; }; -export const deleteKratosIdentity = async (params: { - kratosIdentityId: string; -}): Promise => { +export const deleteKratosIdentity = async (params: { kratosIdentityId: string }): Promise => { await kratosIdentityApi.deleteIdentity({ id: params.kratosIdentityId, }); }; -export const isUserEmailVerified = async ( - kratosIdentityId: string, -): Promise => { +export const isUserEmailVerified = async (kratosIdentityId: string): Promise => { const { data: identity } = await kratosIdentityApi.getIdentity({ id: kratosIdentityId, }); @@ -93,21 +83,17 @@ export const isUserEmailVerified = async ( * using the admin API. This is useful in tests to bypass email verification * when the identity was created without `verifyEmails: true`. */ -export const verifyAllKratosIdentityEmails = async ( - kratosIdentityId: string, -): Promise => { +export const verifyAllKratosIdentityEmails = async (kratosIdentityId: string): Promise => { const { data: identity } = await kratosIdentityApi.getIdentity({ id: kratosIdentityId, }); - const verifiedAddresses = (identity.verifiable_addresses ?? []).map( - (address) => ({ - ...address, - verified: true, - verified_at: address.verified_at ?? new Date().toISOString(), - status: "completed", - }), - ); + const verifiedAddresses = (identity.verifiable_addresses ?? []).map((address) => ({ + ...address, + verified: true, + verified_at: address.verified_at ?? new Date().toISOString(), + status: "completed", + })); await kratosIdentityApi.patchIdentity({ id: kratosIdentityId, diff --git a/apps/hash-api/src/email/create-email-transporter.ts b/apps/hash-api/src/email/create-email-transporter.ts index 18fde6d81ae..dea7345ba55 100644 --- a/apps/hash-api/src/email/create-email-transporter.ts +++ b/apps/hash-api/src/email/create-email-transporter.ts @@ -1,10 +1,7 @@ import path from "node:path"; import { getAwsRegion } from "@local/hash-backend-utils/aws-config"; -import { - getRequiredEnv, - monorepoRootDir, -} from "@local/hash-backend-utils/environment"; +import { getRequiredEnv, monorepoRootDir } from "@local/hash-backend-utils/environment"; import { isDevEnv, isProdEnv, isTestEnv } from "../lib/env-config"; import { logger } from "../logger"; @@ -25,10 +22,7 @@ export const createEmailTransporter = (): EmailTransporter => { return new DummyEmailTransporter({ filePath: process.env.DUMMY_EMAIL_TRANSPORTER_FILE_PATH - ? path.resolve( - monorepoRootDir, - process.env.DUMMY_EMAIL_TRANSPORTER_FILE_PATH, - ) + ? path.resolve(monorepoRootDir, process.env.DUMMY_EMAIL_TRANSPORTER_FILE_PATH) : undefined, }); } diff --git a/apps/hash-api/src/email/transporters/aws-ses-email-transporter.ts b/apps/hash-api/src/email/transporters/aws-ses-email-transporter.ts index 3fbd2b7fe31..303f91735b2 100644 --- a/apps/hash-api/src/email/transporters/aws-ses-email-transporter.ts +++ b/apps/hash-api/src/email/transporters/aws-ses-email-transporter.ts @@ -5,10 +5,7 @@ import nodemailer from "nodemailer"; import { logger } from "../../logger"; -import type { - EmailTransporter, - EmailTransporterSendMailOptions, -} from "./types"; +import type { EmailTransporter, EmailTransporterSendMailOptions } from "./types"; import type SESTransport from "nodemailer/lib/ses-transport"; export interface AwsSesEmailTransporterConfig { diff --git a/apps/hash-api/src/email/transporters/dummy-email-transporter.ts b/apps/hash-api/src/email/transporters/dummy-email-transporter.ts index 137c9308bfa..0be5a25450a 100644 --- a/apps/hash-api/src/email/transporters/dummy-email-transporter.ts +++ b/apps/hash-api/src/email/transporters/dummy-email-transporter.ts @@ -7,10 +7,7 @@ import { dump } from "js-yaml"; import { logger } from "../../logger"; -import type { - EmailTransporter, - EmailTransporterSendMailOptions, -} from "./types"; +import type { EmailTransporter, EmailTransporterSendMailOptions } from "./types"; interface EmailDump { date: string; diff --git a/apps/hash-api/src/email/transporters/smtp-email-transporter.ts b/apps/hash-api/src/email/transporters/smtp-email-transporter.ts index 2dbe081fe39..7c1ad2555ab 100644 --- a/apps/hash-api/src/email/transporters/smtp-email-transporter.ts +++ b/apps/hash-api/src/email/transporters/smtp-email-transporter.ts @@ -5,10 +5,7 @@ import { getRequiredEnv } from "@local/hash-backend-utils/environment"; import { logger } from "../../logger"; -import type { - EmailTransporter, - EmailTransporterSendMailOptions, -} from "./types"; +import type { EmailTransporter, EmailTransporterSendMailOptions } from "./types"; import type SMTPTransport from "nodemailer/lib/smtp-transport"; export interface SmtpEmailTransporterConfig { diff --git a/apps/hash-api/src/generate-ontology-type-ids.ts b/apps/hash-api/src/generate-ontology-type-ids.ts index 5e39533beeb..9e6e9ae2192 100644 --- a/apps/hash-api/src/generate-ontology-type-ids.ts +++ b/apps/hash-api/src/generate-ontology-type-ids.ts @@ -15,10 +15,7 @@ import { currentTimeInstantTemporalAxes } from "@local/hash-isomorphic-utils/gra import { getOrgByShortname } from "./graph/knowledge/system-types/org"; import { isEntityTypeLinkEntityType } from "./graph/ontology/primitive/entity-type"; -import type { - ImpureGraphContext, - ImpureGraphFunction, -} from "./graph/context-types"; +import type { ImpureGraphContext, ImpureGraphFunction } from "./graph/context-types"; import type { Org } from "./graph/knowledge/system-types/org"; import type { DataType, @@ -40,9 +37,7 @@ const convertTitleToCamelCase = (title: string) => .map((word, index) => // If it's the first word, convert it to lowercase // Otherwise, capitalize the first letter and then add the rest of the word in lowercase - index === 0 - ? word.toLowerCase() - : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(), + index === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(), ) // Join all the processed words to get the camelCase result .join(""); @@ -52,10 +47,7 @@ type OntologyTypeWithMetadata = | PropertyTypeWithMetadata | DataTypeWithMetadata; -const serializeTypeIds = ( - types: OntologyTypeWithMetadata[], - isLinkEntityType?: boolean, -) => +const serializeTypeIds = (types: OntologyTypeWithMetadata[], isLinkEntityType?: boolean) => JSON.stringify( types .sort((a, b) => a.schema.title.localeCompare(b.schema.title)) @@ -63,10 +55,10 @@ const serializeTypeIds = ( (prev, { schema }) => ({ ...prev, [convertTitleToCamelCase(schema.title)]: { - [`${isLinkEntityType ? "linkEntityType" : schema.kind}Id`]: + [`${isLinkEntityType ? "linkEntityType" : schema.kind}Id`]: schema.$id, + [`${isLinkEntityType ? "linkEntityType" : schema.kind}BaseUrl`]: extractBaseUrl( schema.$id, - [`${isLinkEntityType ? "linkEntityType" : schema.kind}BaseUrl`]: - extractBaseUrl(schema.$id), + ), ...(schema.kind === "dataType" ? { title: schema.title, @@ -105,10 +97,7 @@ const getLatestBlockprotocolTypesQuery = { equal: [{ path: ["version"] }, { parameter: "latest" }], }, { - startsWith: [ - { path: ["versionedUrl"] }, - { parameter: "https://blockprotocol.org" }, - ], + startsWith: [{ path: ["versionedUrl"] }, { parameter: "https://blockprotocol.org" }], }, ], }, @@ -138,13 +127,7 @@ const serializeTypes: ImpureGraphFunction< await Promise.all( allEntityTypes.map(async (entityType) => { - if ( - await isEntityTypeLinkEntityType( - context, - authentication, - entityType.schema, - ) - ) { + if (await isEntityTypeLinkEntityType(context, authentication, entityType.schema)) { linkEntityTypes.push(entityType); } else { entityTypes.push(entityType); @@ -181,10 +164,7 @@ const generateOntologyIds = async () => { }); const graphApiHost = getRequiredEnv("HASH_GRAPH_HTTP_HOST"); - const graphApiPort = Number.parseInt( - getRequiredEnv("HASH_GRAPH_HTTP_PORT"), - 10, - ); + const graphApiPort = Number.parseInt(getRequiredEnv("HASH_GRAPH_HTTP_PORT"), 10); const graphApi = createGraphClient(logger, { host: graphApiHost, @@ -202,21 +182,9 @@ const generateOntologyIds = async () => { }; const [hashOrg, googleOrg, linearOrg] = await Promise.all([ - getOrgByShortname( - graphContext, - { actorId: publicUserAccountId }, - { shortname: "h" }, - ), - getOrgByShortname( - graphContext, - { actorId: publicUserAccountId }, - { shortname: "google" }, - ), - getOrgByShortname( - graphContext, - { actorId: publicUserAccountId }, - { shortname: "linear" }, - ), + getOrgByShortname(graphContext, { actorId: publicUserAccountId }, { shortname: "h" }), + getOrgByShortname(graphContext, { actorId: publicUserAccountId }, { shortname: "google" }), + getOrgByShortname(graphContext, { actorId: publicUserAccountId }, { shortname: "linear" }), ]); if (!hashOrg) { @@ -284,21 +252,9 @@ const generateOntologyIds = async () => { getLatestTypesInOrganizationQuery({ organization: linearOrg }), ), // BlockProtocol types - queryEntityTypes( - graphContext.graphApi, - authentication, - getLatestBlockprotocolTypesQuery, - ), - queryPropertyTypes( - graphContext.graphApi, - authentication, - getLatestBlockprotocolTypesQuery, - ), - queryDataTypes( - graphContext.graphApi, - authentication, - getLatestBlockprotocolTypesQuery, - ), + queryEntityTypes(graphContext.graphApi, authentication, getLatestBlockprotocolTypesQuery), + queryPropertyTypes(graphContext.graphApi, authentication, getLatestBlockprotocolTypesQuery), + queryDataTypes(graphContext.graphApi, authentication, getLatestBlockprotocolTypesQuery), ]); const outputPath = path.join( diff --git a/apps/hash-api/src/graph/context-types.ts b/apps/hash-api/src/graph/context-types.ts index 3aa96e66a86..e2c4590c0ef 100644 --- a/apps/hash-api/src/graph/context-types.ts +++ b/apps/hash-api/src/graph/context-types.ts @@ -33,6 +33,4 @@ export type ImpureGraphFunction< params: Parameters, ) => ReturnType; -export type PureGraphFunction = ( - params: Parameters, -) => ReturnType; +export type PureGraphFunction = (params: Parameters) => ReturnType; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types.ts index 424f9c671ae..114e19dded5 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types.ts @@ -11,10 +11,7 @@ import { isProdEnv } from "../../lib/env-config"; import { systemAccountId } from "../system-account"; import type { ImpureGraphContext } from "../context-types"; -import type { - MigrationFunction, - MigrationState, -} from "./migrate-ontology-types/types"; +import type { MigrationFunction, MigrationState } from "./migrate-ontology-types/types"; import type { HashInstance } from "@local/hash-backend-utils/hash-instance"; import type { Logger } from "@local/hash-backend-utils/logger"; import type { MigrationsCompletedPropertyValueWithMetadata } from "@local/hash-isomorphic-utils/system-types/hashinstance"; @@ -44,8 +41,7 @@ const saveMigrationState = async (params: { value: migrationsCompleted.map((migration) => ({ value: migration, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, })), } satisfies MigrationsCompletedPropertyValueWithMetadata, @@ -56,8 +52,7 @@ const saveMigrationState = async (params: { property: { value: migrationState, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", }, }, }, @@ -80,10 +75,7 @@ export const migrateOntologyTypes = async (params: { }) => { const authentication = { actorId: systemAccountId }; - const migrationDirectory = path.join( - __dirname, - "migrate-ontology-types/migrations", - ); + const migrationDirectory = path.join(__dirname, "migrate-ontology-types/migrations"); const migrationFileNames = (await readdir(migrationDirectory)) .filter((fileName) => fileName.endsWith(".migration.ts")) @@ -106,9 +98,7 @@ export const migrateOntologyTypes = async (params: { const hashInstance = await getHashInstance(params.context, authentication); const storedMigrationsCompleted = hashInstance.migrationsCompleted; - const storedMigrationState = hashInstance.migrationState as - | MigrationState - | undefined; + const storedMigrationState = hashInstance.migrationState as MigrationState | undefined; if (storedMigrationsCompleted && storedMigrationState) { migrationsCompleted.push(...storedMigrationsCompleted); @@ -179,14 +169,9 @@ export const migrateOntologyTypes = async (params: { * This ensures we can resume from the correct state if the process is interrupted. */ try { - const hashInstance = await getHashInstance( - params.context, - authentication, - ); + const hashInstance = await getHashInstance(params.context, authentication); - const hashInstanceVersion = extractVersion( - hashInstance.entity.metadata.entityTypeIds[0], - ); + const hashInstanceVersion = extractVersion(hashInstance.entity.metadata.entityTypeIds[0]); if (parseInt(hashInstanceVersion, 10) < 2) { params.logger.debug( diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/000-create-first-custom-data-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/000-create-first-custom-data-types.migration.ts index 885234020d0..bd4cdc494cf 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/000-create-first-custom-data-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/000-create-first-custom-data-types.migration.ts @@ -4,11 +4,7 @@ import { createSystemDataTypeIfNotExists } from "../util"; import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], @@ -26,8 +22,7 @@ const migrate: MigrationFunction = async ({ dataTypeDefinition: { allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], title: "Email", - description: - "An identifier for an email box to which messages are delivered.", + description: "An identifier for an email box to which messages are delivered.", format: "email", type: "string", }, @@ -36,96 +31,75 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const lengthDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - abstract: true, - title: "Length", - description: "A measure of distance.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, - }, - ); - - const metricLengthDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: lengthDataType.schema.$id }], - abstract: true, - title: "Metric Length (SI)", - description: - "A measure of distance in the International System of Units (SI), the international standard for decimal-based measurements.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, - }, - ); - - const imperialLengthUkDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: lengthDataType.schema.$id }], - abstract: true, - title: "Imperial Length (UK)", - description: - "A measure of distance in the system of units defined in the British Weights and Measures Acts, in use alongside metric units in the UK and elsewhere.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, - }, - ); - - const imperialLengthUsDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: lengthDataType.schema.$id }], - abstract: true, - title: "Imperial Length (US)", - description: - "A measure of distance in the system of units commonly used in the United States, formally known as United States customary units.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, - }, - ); - - const meterDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: metricLengthDataType.schema.$id }], - title: "Meters", - description: - "The base unit of length in the International System of Units (SI).", - label: { - right: "m", - }, - type: "number", + const lengthDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Length", + description: "A measure of distance.", + type: "number", + }, + conversions: {}, + webShortname: "h", + migrationState, + }); + + const metricLengthDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: lengthDataType.schema.$id }], + abstract: true, + title: "Metric Length (SI)", + description: + "A measure of distance in the International System of Units (SI), the international standard for decimal-based measurements.", + type: "number", + }, + conversions: {}, + webShortname: "h", + migrationState, + }); + + const imperialLengthUkDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: lengthDataType.schema.$id }], + abstract: true, + title: "Imperial Length (UK)", + description: + "A measure of distance in the system of units defined in the British Weights and Measures Acts, in use alongside metric units in the UK and elsewhere.", + type: "number", + }, + conversions: {}, + webShortname: "h", + migrationState, + }); + + const imperialLengthUsDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: lengthDataType.schema.$id }], + abstract: true, + title: "Imperial Length (US)", + description: + "A measure of distance in the system of units commonly used in the United States, formally known as United States customary units.", + type: "number", + }, + conversions: {}, + webShortname: "h", + migrationState, + }); + + const meterDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: metricLengthDataType.schema.$id }], + title: "Meters", + description: "The base unit of length in the International System of Units (SI).", + label: { + right: "m", }, - conversions: {}, - webShortname: "h", - migrationState, + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { @@ -312,8 +286,7 @@ const migrate: MigrationFunction = async ({ dataTypeDefinition: { allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], title: "DateTime", - description: - "A reference to a particular date and time, formatted according to RFC 3339.", + description: "A reference to a particular date and time, formatted according to RFC 3339.", type: "string", format: "date-time", }, @@ -326,8 +299,7 @@ const migrate: MigrationFunction = async ({ dataTypeDefinition: { allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], title: "Time", - description: - "A reference to a particular clock time, formatted according to RFC 3339.", + description: "A reference to a particular clock time, formatted according to RFC 3339.", type: "string", format: "time", }, @@ -336,43 +308,35 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const frequencyDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - abstract: true, - title: "Frequency", - description: - "The number of occurrences of a repeating event per unit of time (temporal frequency).", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, - }, - ); - - const hertzDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: frequencyDataType.schema.$id }], - title: "Hertz", - description: - "A unit of frequency in the International System of Units (SI), equivalent to one cycle per second.", - label: { - right: "Hz", - }, - type: "number", + const frequencyDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Frequency", + description: + "The number of occurrences of a repeating event per unit of time (temporal frequency).", + type: "number", + }, + conversions: {}, + webShortname: "h", + migrationState, + }); + + const hertzDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: frequencyDataType.schema.$id }], + title: "Hertz", + description: + "A unit of frequency in the International System of Units (SI), equivalent to one cycle per second.", + label: { + right: "Hz", }, - conversions: {}, - webShortname: "h", - migrationState, + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { @@ -437,41 +401,33 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const informationDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - abstract: true, - title: "Information", - description: "A measure of information content.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, + const informationDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Information", + description: "A measure of information content.", + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); - const bytesDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: informationDataType.schema.$id }], - title: "Bytes", - description: "A unit of information equal to eight bits.", - label: { - right: "B", - }, - type: "number", + const bytesDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: informationDataType.schema.$id }], + title: "Bytes", + description: "A unit of information equal to eight bits.", + label: { + right: "B", }, - conversions: {}, - webShortname: "h", - migrationState, + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { @@ -573,43 +529,34 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const powerDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - abstract: true, - title: "Power", - description: - "The amount of energy transferred or converted per unit time.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, + const powerDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Power", + description: "The amount of energy transferred or converted per unit time.", + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); - const wattsDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: powerDataType.schema.$id }], - title: "Watts", - description: - "The unit of power or radiant flux in the International System of Units (SI) – the rate at which work is done or energy is transferred. Equal to one joule per second.", - label: { - right: "W", - }, - type: "number", + const wattsDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: powerDataType.schema.$id }], + title: "Watts", + description: + "The unit of power or radiant flux in the International System of Units (SI) – the rate at which work is done or energy is transferred. Equal to one joule per second.", + label: { + right: "W", }, - conversions: {}, - webShortname: "h", - migrationState, + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/001-create-hash-system-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/001-create-hash-system-types.migration.ts index 9637764be7b..6b18887cea7 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/001-create-hash-system-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/001-create-hash-system-types.migration.ts @@ -32,11 +32,7 @@ const blockProtocolEntityTypeIds = [ "https://blockprotocol.org/@hash/types/entity-type/has-query/v/1", ] as const; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** HASH Instance entity type */ const pagesAreEnabledPropertyType = await createSystemPropertyTypeIfNotExists( @@ -45,8 +41,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Pages Are Enabled", - description: - "Whether or not user functionality related to pages is enabled.", + description: "Whether or not user functionality related to pages is enabled.", possibleValues: [{ primitiveDataType: "boolean" }], }, webShortname: "h", @@ -54,20 +49,24 @@ const migrate: MigrationFunction = async ({ }, ); - const userSelfRegistrationIsEnabledPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const userSelfRegistrationIsEnabledPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "User Self Registration Is Enabled", - description: - "Whether or not user self registration (sign-up) is enabled.", + description: "Whether or not user self registration (sign-up) is enabled.", possibleValues: [{ primitiveDataType: "boolean" }], }, webShortname: "h", migrationState, - }); + }, + ); - const orgSelfRegistrationIsEnabledPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const orgSelfRegistrationIsEnabledPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Org Self Registration Is Enabled", description: @@ -76,10 +75,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const userRegistrationByInviteIsEnabledPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const userRegistrationByInviteIsEnabledPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "User Registration By Invitation Is Enabled", description: @@ -88,7 +90,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); await createSystemEntityTypeIfNotExists(context, authentication, { entityTypeDefinition: { @@ -120,8 +123,10 @@ const migrate: MigrationFunction = async ({ /** File entity type */ - const fileStorageBucketPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const fileStorageBucketPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "File Storage Bucket", description: "The bucket in which a file is stored.", @@ -129,22 +134,27 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const fileStorageEndpointPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const fileStorageEndpointPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "File Storage Endpoint", - description: - "The endpoint for making requests to a file storage provider.", + description: "The endpoint for making requests to a file storage provider.", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "h", migrationState, - }); + }, + ); - const fileStorageForcePathStylePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const fileStorageForcePathStylePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "File Storage Force Path Style", description: @@ -153,7 +163,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const fileStorageKeyPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -169,8 +180,10 @@ const migrate: MigrationFunction = async ({ }, ); - const fileStorageProviderPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const fileStorageProviderPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "File Storage Provider", description: "The provider of a file storage service.", @@ -178,10 +191,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const fileStorageRegionPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const fileStorageRegionPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "File Storage Region", description: "The region in which a file is stored.", @@ -189,100 +205,92 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); - - const fileEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "File", - titlePlural: "Files", - description: "A file hosted at a URL", - icon: "/icons/types/file.svg", - labelProperty: - blockProtocolPropertyTypes.displayName.propertyTypeBaseUrl, - properties: [ - { - propertyType: blockProtocolPropertyTypes.fileUrl.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - }, - { - propertyType: blockProtocolPropertyTypes.mimeType.propertyTypeId, - }, - { - propertyType: fileStorageBucketPropertyType, - }, - { - propertyType: fileStorageEndpointPropertyType, - }, - { - propertyType: fileStorageForcePathStylePropertyType, - }, - { - propertyType: fileStorageKeyPropertyType, - }, - { - propertyType: fileStorageProviderPropertyType, - }, - { - propertyType: fileStorageRegionPropertyType, - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/v/1", - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/v/1", - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/v/1", - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/v/1", - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/v/1", - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/v/1", - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/v/1", - }, - ], - }, - webShortname: "h", - migrationState, }, ); + const fileEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "File", + titlePlural: "Files", + description: "A file hosted at a URL", + icon: "/icons/types/file.svg", + labelProperty: blockProtocolPropertyTypes.displayName.propertyTypeBaseUrl, + properties: [ + { + propertyType: blockProtocolPropertyTypes.fileUrl.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + }, + { + propertyType: blockProtocolPropertyTypes.mimeType.propertyTypeId, + }, + { + propertyType: fileStorageBucketPropertyType, + }, + { + propertyType: fileStorageEndpointPropertyType, + }, + { + propertyType: fileStorageForcePathStylePropertyType, + }, + { + propertyType: fileStorageKeyPropertyType, + }, + { + propertyType: fileStorageProviderPropertyType, + }, + { + propertyType: fileStorageRegionPropertyType, + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/v/1", + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/v/1", + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/v/1", + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/v/1", + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/v/1", + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/file-hash/v/1", + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/v/1", + }, + ], + }, + webShortname: "h", + migrationState, + }); + /** Image File entity type */ - const imageFileEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [fileEntityType.schema.$id], - title: "Image File", - titlePlural: "Image Files", - icon: "/icons/types/file-image.svg", - description: "An image file hosted at a URL", - }, - webShortname: "h", - migrationState, + const imageFileEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [fileEntityType.schema.$id], + title: "Image File", + titlePlural: "Image Files", + icon: "/icons/types/file-image.svg", + description: "An image file hosted at a URL", }, - ); + webShortname: "h", + migrationState, + }); /** Block entity type */ @@ -300,51 +308,43 @@ const migrate: MigrationFunction = async ({ }, ); - const hasDataLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Data", - inverse: { - title: "Data For", - }, - description: "The data that something has.", + const hasDataLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Data", + inverse: { + title: "Data For", }, - webShortname: "h", - migrationState, + description: "The data that something has.", }, - ); + webShortname: "h", + migrationState, + }); - const blockEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Block", - titlePlural: "Blocks", - icon: "/icons/types/cube.svg", - description: - "A block that displays or otherwise uses data, part of a wider page or collection.", - properties: [ - { - propertyType: componentIdPropertyType, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasDataLinkEntityType, - minItems: 1, - maxItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, + const blockEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Block", + titlePlural: "Blocks", + icon: "/icons/types/cube.svg", + description: + "A block that displays or otherwise uses data, part of a wider page or collection.", + properties: [ + { + propertyType: componentIdPropertyType, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasDataLinkEntityType, + minItems: 1, + maxItems: 1, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** Block Collection entity type */ @@ -371,8 +371,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Fractional Index", - description: - "The fractional index indicating the current position of something.", + description: "The fractional index indicating the current position of something.", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "h", @@ -380,8 +379,10 @@ const migrate: MigrationFunction = async ({ }, ); - const hasIndexedContentLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const hasIndexedContentLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Has Indexed Content", @@ -398,75 +399,59 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); - - const profileBioEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockCollectionEntityType.schema.$id], - title: "Profile Bio", - titlePlural: "Profile Bios", - icon: "/icons/types/memo-circle-info.svg", - description: - "A biography for display on someone or something's profile.", - outgoingLinks: [ - { - linkEntityType: hasIndexedContentLinkEntityType, - destinationEntityTypes: [blockEntityType], - minItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, }, ); + const profileBioEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockCollectionEntityType.schema.$id], + title: "Profile Bio", + titlePlural: "Profile Bios", + icon: "/icons/types/memo-circle-info.svg", + description: "A biography for display on someone or something's profile.", + outgoingLinks: [ + { + linkEntityType: hasIndexedContentLinkEntityType, + destinationEntityTypes: [blockEntityType], + minItems: 1, + }, + ], + }, + webShortname: "h", + migrationState, + }); + /** Organization entity type */ - const shortnamePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Shortname", - description: "A unique identifier for something, in the form of a slug", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const shortnamePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Shortname", + description: "A unique identifier for something, in the form of a slug", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); - const orgNamePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Organization Name", - description: "The name of an organization.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const orgNamePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Organization Name", + description: "The name of an organization.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); - const locationPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Location", - description: "A location for something, expressed as a single string", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const locationPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Location", + description: "A location for something, expressed as a single string", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); const uriDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "uri", @@ -487,8 +472,10 @@ const migrate: MigrationFunction = async ({ }, ); - const pinnedEntityTypeBaseUrlPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const pinnedEntityTypeBaseUrlPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Pinned Entity Type Base URL", description: "The base URL of a pinned entity type.", @@ -496,24 +483,21 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const hasAvatarLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Avatar", - inverse: { - title: "Avatar For", - }, - description: "The avatar something has.", + const hasAvatarLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Avatar", + inverse: { + title: "Avatar For", }, - webShortname: "h", - migrationState, + description: "The avatar something has.", }, - ); + webShortname: "h", + migrationState, + }); const hasCoverImageLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -532,85 +516,77 @@ const migrate: MigrationFunction = async ({ }, ); - const hasBioLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Bio", - inverse: { - title: "Bio For", - }, - description: "The biography something has.", + const hasBioLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Bio", + inverse: { + title: "Bio For", }, - webShortname: "h", - migrationState, + description: "The biography something has.", }, - ); + webShortname: "h", + migrationState, + }); - const orgEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Organization", - titlePlural: "Organizations", - icon: "/icons/types/people-group.svg", - labelProperty: systemPropertyTypes.organizationName.propertyTypeBaseUrl, - description: - "An organization. Organizations are root-level objects that contain user accounts and teams.", - properties: [ - { - propertyType: shortnamePropertyType, - required: true, - }, - { - propertyType: orgNamePropertyType, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - required: false, - }, - { - propertyType: locationPropertyType, - required: false, - }, - { - propertyType: websiteUrlPropertyType, - required: false, - }, - { - propertyType: pinnedEntityTypeBaseUrlPropertyType, - array: { maxItems: 5 }, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasAvatarLinkEntityType, - destinationEntityTypes: [imageFileEntityType], - maxItems: 1, - minItems: 0, - }, - { - linkEntityType: hasCoverImageLinkEntityType, - destinationEntityTypes: [imageFileEntityType], - maxItems: 1, - minItems: 0, - }, - { - linkEntityType: hasBioLinkEntityType, - destinationEntityTypes: [profileBioEntityType], - minItems: 0, - maxItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, + const orgEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Organization", + titlePlural: "Organizations", + icon: "/icons/types/people-group.svg", + labelProperty: systemPropertyTypes.organizationName.propertyTypeBaseUrl, + description: + "An organization. Organizations are root-level objects that contain user accounts and teams.", + properties: [ + { + propertyType: shortnamePropertyType, + required: true, + }, + { + propertyType: orgNamePropertyType, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + required: false, + }, + { + propertyType: locationPropertyType, + required: false, + }, + { + propertyType: websiteUrlPropertyType, + required: false, + }, + { + propertyType: pinnedEntityTypeBaseUrlPropertyType, + array: { maxItems: 5 }, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasAvatarLinkEntityType, + destinationEntityTypes: [imageFileEntityType], + maxItems: 1, + minItems: 0, + }, + { + linkEntityType: hasCoverImageLinkEntityType, + destinationEntityTypes: [imageFileEntityType], + maxItems: 1, + minItems: 0, + }, + { + linkEntityType: hasBioLinkEntityType, + destinationEntityTypes: [profileBioEntityType], + minItems: 0, + maxItems: 1, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** Service Account entity type */ @@ -744,22 +720,20 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const emailPropertyType = await createSystemPropertyTypeIfNotExists( + const emailPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Email", + description: "An email address", + possibleValues: [{ dataTypeId: emailDataTypeId }], + }, + webShortname: "h", + migrationState, + }); + + const kratosIdentityIdPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { - propertyTypeDefinition: { - title: "Email", - description: "An email address", - possibleValues: [{ dataTypeId: emailDataTypeId }], - }, - webShortname: "h", - migrationState, - }, - ); - - const kratosIdentityIdPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { propertyTypeDefinition: { title: "Kratos Identity Id", description: "An identifier for a record in Ory Kratos.", @@ -767,7 +741,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const preferredNamePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -783,8 +758,10 @@ const migrate: MigrationFunction = async ({ }, ); - const preferredPronounsPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const preferredPronounsPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Preferred Pronouns", description: "Someone's preferred pronouns.", @@ -792,7 +769,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const isMemberOfLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -811,8 +789,10 @@ const migrate: MigrationFunction = async ({ }, ); - const hasServiceAccountLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const hasServiceAccountLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Has Service Account", @@ -823,278 +803,233 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); - - const userEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "User", - titlePlural: "Users", - icon: "/icons/types/user.svg", - description: "A user of the HASH application.", - properties: [ - { - propertyType: shortnamePropertyType, - }, - { - propertyType: emailPropertyType, - required: true, - array: { minItems: 1 }, - }, - { - propertyType: kratosIdentityIdPropertyType, - required: true, - }, - { - propertyType: preferredNamePropertyType, - }, - { - propertyType: preferredPronounsPropertyType, - }, - { - propertyType: locationPropertyType, - }, - { - propertyType: websiteUrlPropertyType, - }, - { - propertyType: pinnedEntityTypeBaseUrlPropertyType, - array: { maxItems: 5 }, - }, - ], - outgoingLinks: [ - { - linkEntityType: isMemberOfLinkEntityType, - destinationEntityTypes: [orgEntityType], - }, - { - linkEntityType: hasAvatarLinkEntityType, - destinationEntityTypes: [imageFileEntityType], - maxItems: 1, - minItems: 0, - }, - { - linkEntityType: hasCoverImageLinkEntityType, - destinationEntityTypes: [imageFileEntityType], - maxItems: 1, - minItems: 0, - }, - { - linkEntityType: hasServiceAccountLinkEntityType, - destinationEntityTypes: [serviceAccountEntityType], - }, - { - linkEntityType: hasBioLinkEntityType, - destinationEntityTypes: [profileBioEntityType], - minItems: 0, - maxItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, }, ); + const userEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "User", + titlePlural: "Users", + icon: "/icons/types/user.svg", + description: "A user of the HASH application.", + properties: [ + { + propertyType: shortnamePropertyType, + }, + { + propertyType: emailPropertyType, + required: true, + array: { minItems: 1 }, + }, + { + propertyType: kratosIdentityIdPropertyType, + required: true, + }, + { + propertyType: preferredNamePropertyType, + }, + { + propertyType: preferredPronounsPropertyType, + }, + { + propertyType: locationPropertyType, + }, + { + propertyType: websiteUrlPropertyType, + }, + { + propertyType: pinnedEntityTypeBaseUrlPropertyType, + array: { maxItems: 5 }, + }, + ], + outgoingLinks: [ + { + linkEntityType: isMemberOfLinkEntityType, + destinationEntityTypes: [orgEntityType], + }, + { + linkEntityType: hasAvatarLinkEntityType, + destinationEntityTypes: [imageFileEntityType], + maxItems: 1, + minItems: 0, + }, + { + linkEntityType: hasCoverImageLinkEntityType, + destinationEntityTypes: [imageFileEntityType], + maxItems: 1, + minItems: 0, + }, + { + linkEntityType: hasServiceAccountLinkEntityType, + destinationEntityTypes: [serviceAccountEntityType], + }, + { + linkEntityType: hasBioLinkEntityType, + destinationEntityTypes: [profileBioEntityType], + minItems: 0, + maxItems: 1, + }, + ], + }, + webShortname: "h", + migrationState, + }); + /** Text entity type */ - const textEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Text", - titlePlural: "Texts", - icon: "/icons/types/text.svg", - description: "An ordered sequence of characters.", - properties: [ - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/v/2", - required: true, - }, - ], - }, - webShortname: "h", - migrationState, + const textEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Text", + titlePlural: "Texts", + icon: "/icons/types/text.svg", + description: "An ordered sequence of characters.", + properties: [ + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/v/2", + required: true, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** Page entity type */ - const archivedPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - possibleValues: [{ primitiveDataType: "boolean" }], - title: "Archived", - description: "Whether or not something has been archived.", - }, - webShortname: "h", - migrationState, + const archivedPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + possibleValues: [{ primitiveDataType: "boolean" }], + title: "Archived", + description: "Whether or not something has been archived.", }, - ); + webShortname: "h", + migrationState, + }); - const summaryPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Summary", - description: "The summary of the something.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const summaryPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Summary", + description: "The summary of the something.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); - const titlePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Title", - description: "The title of something.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const titlePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Title", + description: "The title of something.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); - const iconPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Icon", - description: "An emoji icon.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const iconPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Icon", + description: "An emoji icon.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); - const hasParentLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Parent", - inverse: { - title: "Parent Of", - }, - description: "The parent something has.", + const hasParentLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Parent", + inverse: { + title: "Parent Of", }, - webShortname: "h", - migrationState, + description: "The parent something has.", }, - ); + webShortname: "h", + migrationState, + }); - const pageEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockCollectionEntityType.schema.$id], - title: "Page", - titlePlural: "Pages", - icon: "/icons/types/page.svg", - labelProperty: systemPropertyTypes.title.propertyTypeBaseUrl, - description: - "A page for displaying and potentially interacting with data.", - properties: [ - { - propertyType: summaryPropertyType, - }, - { - propertyType: archivedPropertyType, - }, - { - propertyType: iconPropertyType, - }, - { - propertyType: titlePropertyType, - required: true, - }, - { - propertyType: fractionalIndexPropertyType, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasParentLinkEntityType, - destinationEntityTypes: ["SELF_REFERENCE"], - maxItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, + const pageEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockCollectionEntityType.schema.$id], + title: "Page", + titlePlural: "Pages", + icon: "/icons/types/page.svg", + labelProperty: systemPropertyTypes.title.propertyTypeBaseUrl, + description: "A page for displaying and potentially interacting with data.", + properties: [ + { + propertyType: summaryPropertyType, + }, + { + propertyType: archivedPropertyType, + }, + { + propertyType: iconPropertyType, + }, + { + propertyType: titlePropertyType, + required: true, + }, + { + propertyType: fractionalIndexPropertyType, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasParentLinkEntityType, + destinationEntityTypes: ["SELF_REFERENCE"], + maxItems: 1, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** Document entity type */ - const _documentEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Document", - titlePlural: "Documents", - description: - "A page in document format, with content arranged in columns.", - allOf: [pageEntityType.schema.$id], - outgoingLinks: [ - { - linkEntityType: hasIndexedContentLinkEntityType, - destinationEntityTypes: [blockEntityType], - minItems: 0, - }, - ], - }, - webShortname: "h", - migrationState, + const _documentEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Document", + titlePlural: "Documents", + description: "A page in document format, with content arranged in columns.", + allOf: [pageEntityType.schema.$id], + outgoingLinks: [ + { + linkEntityType: hasIndexedContentLinkEntityType, + destinationEntityTypes: [blockEntityType], + minItems: 0, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** Canvas entity type */ - const xPositionPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "X Position", - description: "The position of something on the x axis.", - possibleValues: [{ primitiveDataType: "number" }], - }, - webShortname: "h", - migrationState, + const xPositionPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "X Position", + description: "The position of something on the x axis.", + possibleValues: [{ primitiveDataType: "number" }], }, - ); + webShortname: "h", + migrationState, + }); - const yPositionPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Y Position", - description: "The position of something on the y axis.", - possibleValues: [{ primitiveDataType: "number" }], - }, - webShortname: "h", - migrationState, + const yPositionPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Y Position", + description: "The position of something on the y axis.", + possibleValues: [{ primitiveDataType: "number" }], }, - ); + webShortname: "h", + migrationState, + }); const heightInPixelsPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -1138,8 +1073,10 @@ const migrate: MigrationFunction = async ({ }, ); - const hasSpatiallyPositionedContentLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const hasSpatiallyPositionedContentLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Has Spatially Positioned Content", @@ -1155,41 +1092,18 @@ const migrate: MigrationFunction = async ({ { propertyType: yPositionPropertyType, required: true, - }, - { - propertyType: heightInPixelsPropertyType, - required: true, - }, - { - propertyType: widthInPixelsPropertyType, - required: true, - }, - { - propertyType: rotationInRadsPropertyType, - required: true, - }, - ], - }, - webShortname: "h", - migrationState, - }); - - const _canvasEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Canvas", - titlePlural: "Canvases", - icon: "/icons/types/rectangle.svg", - description: - "A page in canvas format, with content in a free-form arrangement.", - allOf: [pageEntityType.schema.$id], - outgoingLinks: [ + }, { - linkEntityType: hasSpatiallyPositionedContentLinkEntityType, - destinationEntityTypes: [blockEntityType], - minItems: 0, + propertyType: heightInPixelsPropertyType, + required: true, + }, + { + propertyType: widthInPixelsPropertyType, + required: true, + }, + { + propertyType: rotationInRadsPropertyType, + required: true, }, ], }, @@ -1198,69 +1112,69 @@ const migrate: MigrationFunction = async ({ }, ); + const _canvasEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Canvas", + titlePlural: "Canvases", + icon: "/icons/types/rectangle.svg", + description: "A page in canvas format, with content in a free-form arrangement.", + allOf: [pageEntityType.schema.$id], + outgoingLinks: [ + { + linkEntityType: hasSpatiallyPositionedContentLinkEntityType, + destinationEntityTypes: [blockEntityType], + minItems: 0, + }, + ], + }, + webShortname: "h", + migrationState, + }); + /** Quick Note entity */ - const _quickNoteEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockCollectionEntityType.schema.$id], - title: "Note", - titlePlural: "Notes", - icon: "/icons/types/note-sticky.svg", - description: "A (usually) quick or short note.", - properties: [{ propertyType: archivedPropertyType }], - outgoingLinks: [ - { - linkEntityType: hasIndexedContentLinkEntityType, - destinationEntityTypes: [blockEntityType], - minItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, + const _quickNoteEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockCollectionEntityType.schema.$id], + title: "Note", + titlePlural: "Notes", + icon: "/icons/types/note-sticky.svg", + description: "A (usually) quick or short note.", + properties: [{ propertyType: archivedPropertyType }], + outgoingLinks: [ + { + linkEntityType: hasIndexedContentLinkEntityType, + destinationEntityTypes: [blockEntityType], + minItems: 1, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); const dateTimeDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "datetime", migrationState, }); - const expiredAtPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Expired At", - description: "Stringified timestamp of when something expired.", - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "h", - migrationState, + const expiredAtPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Expired At", + description: "Stringified timestamp of when something expired.", + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, - ); - - const connectionSourceNamePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Connection Source Name", - description: "The name of the connection source.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, - }); + webShortname: "h", + migrationState, + }); - const vaultPathPropertyType = await createSystemPropertyTypeIfNotExists( + const connectionSourceNamePropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "Vault Path", - description: "The path to a secret in Hashicorp Vault.", + title: "Connection Source Name", + description: "The name of the connection source.", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "h", @@ -1268,6 +1182,16 @@ const migrate: MigrationFunction = async ({ }, ); + const vaultPathPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Vault Path", + description: "The path to a secret in Hashicorp Vault.", + possibleValues: [{ primitiveDataType: "text" }], + }, + webShortname: "h", + migrationState, + }); + const linearTeamIdPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, @@ -1282,8 +1206,10 @@ const migrate: MigrationFunction = async ({ }, ); - const syncLinearDataWithLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const syncLinearDataWithLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Sync Linear Data With", @@ -1297,7 +1223,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const usesUserSecretLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -1316,34 +1243,30 @@ const migrate: MigrationFunction = async ({ }, ); - const userSecretEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "User Secret", - titlePlural: "User Secrets", - icon: "/icons/types/user-lock.svg", - description: "A secret or credential belonging to a user.", - properties: [ - { - propertyType: expiredAtPropertyType, - required: true, - }, - { - propertyType: connectionSourceNamePropertyType, - required: true, - }, - { - propertyType: vaultPathPropertyType, - required: true, - }, - ], - }, - webShortname: "h", - migrationState, + const userSecretEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "User Secret", + titlePlural: "User Secrets", + icon: "/icons/types/user-lock.svg", + description: "A secret or credential belonging to a user.", + properties: [ + { + propertyType: expiredAtPropertyType, + required: true, + }, + { + propertyType: connectionSourceNamePropertyType, + required: true, + }, + { + propertyType: vaultPathPropertyType, + required: true, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); const linearOrgIdPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -1406,36 +1329,28 @@ const migrate: MigrationFunction = async ({ }, ); - const deletedAtPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Deleted At", - description: "Stringified timestamp of when something was deleted.", - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "h", - migrationState, + const deletedAtPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Deleted At", + description: "Stringified timestamp of when something was deleted.", + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, - ); + webShortname: "h", + migrationState, + }); - const hasTextLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Text", - inverse: { - title: "Text For", - }, - description: "The text something has.", + const hasTextLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Text", + inverse: { + title: "Text For", }, - webShortname: "h", - migrationState, + description: "The text something has.", }, - ); + webShortname: "h", + migrationState, + }); const authoredByLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -1455,92 +1370,82 @@ const migrate: MigrationFunction = async ({ }, ); - const commentEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Comment", - titlePlural: "Comments", - icon: "/icons/types/comment.svg", - description: "Comment associated with the issue.", - properties: [ - { - propertyType: resolvedAtPropertyType, - }, - { - propertyType: deletedAtPropertyType, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasTextLinkEntityType, - destinationEntityTypes: [textEntityType], - minItems: 1, - maxItems: 1, - }, - { - linkEntityType: hasParentLinkEntityType, - destinationEntityTypes: ["SELF_REFERENCE", blockEntityType], - minItems: 1, - maxItems: 1, - }, - { - linkEntityType: authoredByLinkEntityType, - destinationEntityTypes: [userEntityType], - minItems: 1, - maxItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, + const commentEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Comment", + titlePlural: "Comments", + icon: "/icons/types/comment.svg", + description: "Comment associated with the issue.", + properties: [ + { + propertyType: resolvedAtPropertyType, + }, + { + propertyType: deletedAtPropertyType, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasTextLinkEntityType, + destinationEntityTypes: [textEntityType], + minItems: 1, + maxItems: 1, + }, + { + linkEntityType: hasParentLinkEntityType, + destinationEntityTypes: ["SELF_REFERENCE", blockEntityType], + minItems: 1, + maxItems: 1, + }, + { + linkEntityType: authoredByLinkEntityType, + destinationEntityTypes: [userEntityType], + minItems: 1, + maxItems: 1, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** Notification entity type */ - const readAtPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Read At", - description: "The timestamp of when something was read.", - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "h", - migrationState, + const readAtPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Read At", + description: "The timestamp of when something was read.", + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, - ); + webShortname: "h", + migrationState, + }); - const notificationEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Notification", - titlePlural: "Notifications", - icon: "/icons/types/megaphone.svg", - description: "A notification to a user.", - properties: [ - { - propertyType: archivedPropertyType, - }, - { - propertyType: readAtPropertyType, - }, - ], - }, - webShortname: "h", - migrationState, + const notificationEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Notification", + titlePlural: "Notifications", + icon: "/icons/types/megaphone.svg", + description: "A notification to a user.", + properties: [ + { + propertyType: archivedPropertyType, + }, + { + propertyType: readAtPropertyType, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** Mention Notification entity type */ - const occurredInEntityLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const occurredInEntityLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Occurred In Entity", @@ -1551,7 +1456,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const occurredInBlockLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -1570,8 +1476,10 @@ const migrate: MigrationFunction = async ({ }, ); - const occurredInCommentLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const occurredInCommentLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Occurred In Comment", @@ -1582,7 +1490,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const occurredInTextLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -1618,8 +1527,10 @@ const migrate: MigrationFunction = async ({ }, ); - const _mentionNotificationEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const _mentionNotificationEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [notificationEntityType.schema.$id], title: "Mention Notification", @@ -1660,12 +1571,15 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); /** Comment Notification entity type */ - const triggeredByCommentLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const triggeredByCommentLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Triggered By Comment", @@ -1676,10 +1590,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const repliedToCommentLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const repliedToCommentLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Replied To Comment", @@ -1690,10 +1607,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const _commentNotificationEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const _commentNotificationEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { title: "Comment Notification", titlePlural: "Comment Notifications", @@ -1734,21 +1654,18 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); /** * Ensure the primitive BP data types are loaded */ await Promise.all([ ...blockProtocolDataTypeIds.map(async (dataTypeId) => { - const existingDataType = await getDataTypeById( - context.graphApi, - authentication, - { - dataTypeId, - temporalAxes: fullTransactionTimeAxis, - }, - ); + const existingDataType = await getDataTypeById(context.graphApi, authentication, { + dataTypeId, + temporalAxes: fullTransactionTimeAxis, + }); if (existingDataType) { return; @@ -1759,14 +1676,10 @@ const migrate: MigrationFunction = async ({ }); }), ...blockProtocolEntityTypeIds.map(async (entityTypeId) => { - const existingEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId, - temporalAxes: fullTransactionTimeAxis, - }, - ); + const existingEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId, + temporalAxes: fullTransactionTimeAxis, + }); if (existingEntityType) { return; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/003-create-linear-system-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/003-create-linear-system-types.migration.ts index 635cd9be642..c7749ceceba 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/003-create-linear-system-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/003-create-linear-system-types.migration.ts @@ -10,19 +10,17 @@ import { import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { if (!enabledIntegrations.linear) { return migrationState; } /** Linear Organization entity type */ - const allowMembersToInvitePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const allowMembersToInvitePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Allow Members To Invite", description: "Whether member users are allowed to send invites.", @@ -30,19 +28,22 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); - const allowedAuthServicePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const allowedAuthServicePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Allowed Auth Service", - description: - "Allowed authentication provider, empty array means all are allowed.", + description: "Allowed authentication provider, empty array means all are allowed.", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "linear", migrationState, - }); + }, + ); const dateTimeDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "datetime", @@ -64,22 +65,20 @@ const migrate: MigrationFunction = async ({ }, ); - const createdAtPropertyType = await createSystemPropertyTypeIfNotExists( + const createdAtPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Created At", + description: "The time at which the entity was created.", + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], + }, + webShortname: "linear", + migrationState, + }); + + const createdIssueCountPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { - propertyTypeDefinition: { - title: "Created At", - description: "The time at which the entity was created.", - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "linear", - migrationState, - }, - ); - - const createdIssueCountPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { propertyTypeDefinition: { title: "Created Issue Count", description: "Number of issues created.", @@ -87,19 +86,22 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); - const deletionRequestedAtPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const deletionRequestedAtPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Deletion Requested At", - description: - "The time at which deletion of the organization was requested.", + description: "The time at which deletion of the organization was requested.", possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, webShortname: "linear", migrationState, - }); + }, + ); const gitBranchFormatPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -107,8 +109,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Git Branch Format", - description: - "How git branches are formatted. If null, default formatting will be used.", + description: "How git branches are formatted. If null, default formatting will be used.", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "linear", @@ -116,8 +117,10 @@ const migrate: MigrationFunction = async ({ }, ); - const gitLinkbackMessagesEnabledPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const gitLinkbackMessagesEnabledPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Git Linkback Messages Enabled", description: @@ -126,10 +129,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); - const gitPublicLinkbackMessagesEnabledPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const gitPublicLinkbackMessagesEnabledPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Git Public Linkback Messages Enabled", description: @@ -138,71 +144,62 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); - - const idPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "ID", - description: "The unique identifier of the entity.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, }, ); + const idPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "ID", + description: "The unique identifier of the entity.", + possibleValues: [{ primitiveDataType: "text" }], + }, + webShortname: "linear", + migrationState, + }); + const uriDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "uri", migrationState, }); - const logoUrlPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Logo URL", - description: "The organization's logo URL.", - possibleValues: [{ dataTypeId: uriDataTypeId }], - }, - webShortname: "linear", - migrationState, + const logoUrlPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Logo URL", + description: "The organization's logo URL.", + possibleValues: [{ dataTypeId: uriDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); - const namePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Name", - description: "The organization's name.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, + const namePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Name", + description: "The organization's name.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "linear", + migrationState, + }); const megabytesDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "megabytes", migrationState, }); - const periodUploadVolumePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const periodUploadVolumePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Period Upload Volume", - description: - "Rolling 30-day total upload volume for the organization, in megabytes.", + description: "Rolling 30-day total upload volume for the organization, in megabytes.", possibleValues: [{ dataTypeId: megabytesDataTypeId }], }, webShortname: "linear", migrationState, - }); + }, + ); const previousUrlKeysPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -219,8 +216,10 @@ const migrate: MigrationFunction = async ({ }, ); - const projectUpdateRemindersHourPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const projectUpdateRemindersHourPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Project Update Reminders Hour", description: "The hour at which to prompt for project updates.", @@ -228,7 +227,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); const roadmapEnabledPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -286,52 +286,40 @@ const migrate: MigrationFunction = async ({ }, ); - const updatedAtPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Updated At", - description: [ - "The last time at which the entity was meaningfully updated,", - "i.e. for all changes of syncable properties except those", - "for which updates should not produce an update to updatedAt (see skipUpdatedAtKeys).", - "This is the same as the creation time if the entity hasn't been updated after creation.", - ].join(" "), - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "linear", - migrationState, + const updatedAtPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Updated At", + description: [ + "The last time at which the entity was meaningfully updated,", + "i.e. for all changes of syncable properties except those", + "for which updates should not produce an update to updatedAt (see skipUpdatedAtKeys).", + "This is the same as the creation time if the entity hasn't been updated after creation.", + ].join(" "), + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); - const urlKeyPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "URL Key", - description: "The organization's unique URL key.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, + const urlKeyPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "URL Key", + description: "The organization's unique URL key.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "linear", + migrationState, + }); - const userCountPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "User Count", - description: "Number of active users in the organization.", - possibleValues: [{ primitiveDataType: "number" }], - }, - webShortname: "linear", - migrationState, + const userCountPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "User Count", + description: "Number of active users in the organization.", + possibleValues: [{ primitiveDataType: "number" }], }, - ); + webShortname: "linear", + migrationState, + }); const linearOrganizationEntityType = await createSystemEntityTypeIfNotExists( context, @@ -446,48 +434,35 @@ const migrate: MigrationFunction = async ({ /** Linear User entity type */ - const activePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Active", - description: - "Whether the user account is active or disabled (suspended).", - possibleValues: [{ primitiveDataType: "boolean" }], - }, - webShortname: "linear", - migrationState, + const activePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Active", + description: "Whether the user account is active or disabled (suspended).", + possibleValues: [{ primitiveDataType: "boolean" }], }, - ); + webShortname: "linear", + migrationState, + }); - const adminPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Admin", - description: " Whether the user is an organization administrator.", - possibleValues: [{ primitiveDataType: "boolean" }], - }, - webShortname: "linear", - migrationState, + const adminPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Admin", + description: " Whether the user is an organization administrator.", + possibleValues: [{ primitiveDataType: "boolean" }], }, - ); + webShortname: "linear", + migrationState, + }); - const avatarUrlPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Avatar URL", - description: "An URL to the user's avatar image.", - possibleValues: [{ dataTypeId: uriDataTypeId }], - }, - webShortname: "linear", - migrationState, + const avatarUrlPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Avatar URL", + description: "An URL to the user's avatar image.", + possibleValues: [{ dataTypeId: uriDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); const disableReasonPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -509,8 +484,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Display Name", - description: - "The user's display (nick) name. Unique within each organization.", + description: "The user's display (nick) name. Unique within each organization.", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "linear", @@ -523,20 +497,16 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const guestPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Guest", - description: - "Whether the user is a guest in the workspace and limited to accessing a subset of teams.", - possibleValues: [{ primitiveDataType: "boolean" }], - }, - webShortname: "linear", - migrationState, + const guestPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Guest", + description: + "Whether the user is a guest in the workspace and limited to accessing a subset of teams.", + possibleValues: [{ primitiveDataType: "boolean" }], }, - ); + webShortname: "linear", + migrationState, + }); const inviteHashPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -552,51 +522,40 @@ const migrate: MigrationFunction = async ({ }, ); - const isMePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Is Me", - description: " Whether the user is the currently authenticated user.", - possibleValues: [{ primitiveDataType: "boolean" }], - }, - webShortname: "linear", - migrationState, + const isMePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Is Me", + description: " Whether the user is the currently authenticated user.", + possibleValues: [{ primitiveDataType: "boolean" }], }, - ); + webShortname: "linear", + migrationState, + }); - const lastSeenPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Last Seen", - description: - "The last time the user was seen online. If null, the user is currently online.", - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "linear", - migrationState, + const lastSeenPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Last Seen", + description: "The last time the user was seen online. If null, the user is currently online.", + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); + + const fullNamePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Full Name", + description: "The user's full name.", + possibleValues: [{ primitiveDataType: "text" }], + }, + webShortname: "linear", + migrationState, + }); - const fullNamePropertyType = await createSystemPropertyTypeIfNotExists( + const belongsToOrganizationLinkEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { - propertyTypeDefinition: { - title: "Full Name", - description: "The user's full name.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, - }, - ); - - const belongsToOrganizationLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Belongs To Organization", @@ -605,7 +564,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); const statusEmojiPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -641,8 +601,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Status Until At", - description: - "A date at which the user current status should be cleared.", + description: "A date at which the user current status should be cleared.", possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, webShortname: "linear", @@ -650,19 +609,15 @@ const migrate: MigrationFunction = async ({ }, ); - const timezonePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Timezone", - description: "The local timezone of the user.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, + const timezonePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Timezone", + description: "The local timezone of the user.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "linear", + migrationState, + }); const profileUrlPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -693,149 +648,140 @@ const migrate: MigrationFunction = async ({ }, ); - const linearUserEntityType = await createSystemEntityTypeIfNotExists( + const linearUserEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "User", + description: "A user that has access to the resources of an organization.", + properties: [ + { + propertyType: activePropertyType, + required: true, + }, + { + propertyType: adminPropertyType, + required: true, + }, + { + propertyType: archivedAtPropertyType, + }, + { + propertyType: avatarUrlPropertyType, + }, + { + propertyType: createdAtPropertyType, + required: true, + }, + { + propertyType: createdIssueCountPropertyType, + required: true, + }, + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/description/v/1", + }, + { + propertyType: disableReasonPropertyType, + }, + { + propertyType: displayNamePropertyType, + required: true, + }, + { + propertyType: emailPropertyTypeId, + required: true, + }, + { + propertyType: guestPropertyType, + required: true, + }, + { + propertyType: idPropertyType, + required: true, + }, + { + propertyType: inviteHashPropertyType, + required: true, + }, + { + propertyType: isMePropertyType, + required: true, + }, + { + propertyType: lastSeenPropertyType, + }, + { + propertyType: fullNamePropertyType, + required: true, + }, + { + propertyType: statusEmojiPropertyType, + }, + { + propertyType: statusLabelPropertyType, + }, + { + propertyType: statusUntilAtPropertyType, + }, + { + propertyType: timezonePropertyType, + }, + { + propertyType: updatedAtPropertyType, + required: true, + }, + { + propertyType: profileUrlPropertyType, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: belongsToOrganizationLinkEntityType, + minItems: 1, + maxItems: 1, + destinationEntityTypes: [linearOrganizationEntityType], + }, + /** @todo: team memberships */ + ], + }, + webShortname: "linear", + migrationState, + }); + + /** Linear Workflow State entity type */ + + const workflowStateEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Workflow State", + description: "A state in a team workflow.", + }, + webShortname: "linear", + migrationState, + }); + + /** Linear Issue entity type */ + + const hasAssigneeLinkEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { entityTypeDefinition: { - title: "User", - description: - "A user that has access to the resources of an organization.", - properties: [ - { - propertyType: activePropertyType, - required: true, - }, - { - propertyType: adminPropertyType, - required: true, - }, - { - propertyType: archivedAtPropertyType, - }, - { - propertyType: avatarUrlPropertyType, - }, - { - propertyType: createdAtPropertyType, - required: true, - }, - { - propertyType: createdIssueCountPropertyType, - required: true, - }, - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/description/v/1", - }, - { - propertyType: disableReasonPropertyType, - }, - { - propertyType: displayNamePropertyType, - required: true, - }, - { - propertyType: emailPropertyTypeId, - required: true, - }, - { - propertyType: guestPropertyType, - required: true, - }, - { - propertyType: idPropertyType, - required: true, - }, - { - propertyType: inviteHashPropertyType, - required: true, - }, - { - propertyType: isMePropertyType, - required: true, - }, - { - propertyType: lastSeenPropertyType, - }, - { - propertyType: fullNamePropertyType, - required: true, - }, - { - propertyType: statusEmojiPropertyType, - }, - { - propertyType: statusLabelPropertyType, - }, - { - propertyType: statusUntilAtPropertyType, - }, - { - propertyType: timezonePropertyType, - }, - { - propertyType: updatedAtPropertyType, - required: true, - }, - { - propertyType: profileUrlPropertyType, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: belongsToOrganizationLinkEntityType, - minItems: 1, - maxItems: 1, - destinationEntityTypes: [linearOrganizationEntityType], - }, - /** @todo: team memberships */ - ], - }, - webShortname: "linear", - migrationState, - }, - ); - - /** Linear Workflow State entity type */ - - const workflowStateEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Workflow State", - description: "A state in a team workflow.", - }, - webShortname: "linear", - migrationState, - }, - ); - - /** Linear Issue entity type */ - - const hasAssigneeLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Assignee", - description: "The user to whom the issue is assigned to.", - properties: [], - }, - webShortname: "linear", - migrationState, - }, - ); - - const autoArchivedAtPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Auto Archived At", + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Assignee", + description: "The user to whom the issue is assigned to.", + properties: [], + }, + webShortname: "linear", + migrationState, + }, + ); + + const autoArchivedAtPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { + propertyTypeDefinition: { + title: "Auto Archived At", description: "The time at which the issue was automatically archived by the auto pruning process.", possibleValues: [{ dataTypeId: dateTimeDataTypeId }], @@ -880,8 +826,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Canceled At", - description: - "The time at which the issue was moved into canceled state.", + description: "The time at which the issue was moved into canceled state.", possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, webShortname: "linear", @@ -895,8 +840,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Completed At", - description: - "The time at which the issue was moved into completed state.", + description: "The time at which the issue was moved into completed state.", possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, webShortname: "linear", @@ -904,8 +848,10 @@ const migrate: MigrationFunction = async ({ }, ); - const customerTicketCountPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const customerTicketCountPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Customer Ticket Count", description: @@ -914,10 +860,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); - const _associatedWithCycleLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const _associatedWithCycleLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Associated With Cycle", @@ -926,10 +875,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); - const markdownDescriptionPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const markdownDescriptionPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Markdown Description", description: "The issue's description in markdown format.", @@ -937,53 +889,48 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); const dateDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "date", migrationState, }); - const dueDatePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Due Date", - description: "The date at which the issue is due.", - possibleValues: [{ dataTypeId: dateDataTypeId }], - }, - webShortname: "linear", - migrationState, + const dueDatePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Due Date", + description: "The date at which the issue is due.", + possibleValues: [{ dataTypeId: dateDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); + + const estimatePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Estimate", + description: "The estimate of the complexity of the issue.", + possibleValues: [{ primitiveDataType: "number" }], + }, + webShortname: "linear", + migrationState, + }); - const estimatePropertyType = await createSystemPropertyTypeIfNotExists( + const integrationSourceTypePropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { - propertyTypeDefinition: { - title: "Estimate", - description: "The estimate of the complexity of the issue.", - possibleValues: [{ primitiveDataType: "number" }], - }, - webShortname: "linear", - migrationState, - }, - ); - - const integrationSourceTypePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { propertyTypeDefinition: { title: "Integration Source Type", - description: - "Integration type that created this issue, if applicable. (e.g. slack)", + description: "Integration type that created this issue, if applicable. (e.g. slack)", /** @todo: convert to union */ possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "linear", migrationState, - }); + }, + ); const identifierPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -1013,48 +960,42 @@ const migrate: MigrationFunction = async ({ }, ); - const parentLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Parent", - description: "The parent of the issue.", - properties: [], - }, - webShortname: "linear", - migrationState, + const parentLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Parent", + description: "The parent of the issue.", + properties: [], }, - ); - - const previousIdentifierPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Previous Identifier", - description: - "Previous identifier of the issue if it has been moved between teams.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, - }); + webShortname: "linear", + migrationState, + }); - const priorityPropertyType = await createSystemPropertyTypeIfNotExists( + const previousIdentifierPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "Priority", - description: - "The priority of the issue. 0 = No priority, 1 = Urgent, 2 = High, 3 = Normal, 4 = Low.", - possibleValues: [{ primitiveDataType: "number" }], + title: "Previous Identifier", + description: "Previous identifier of the issue if it has been moved between teams.", + possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "linear", migrationState, }, ); + const priorityPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Priority", + description: + "The priority of the issue. 0 = No priority, 1 = Urgent, 2 = High, 3 = Normal, 4 = Low.", + possibleValues: [{ primitiveDataType: "number" }], + }, + webShortname: "linear", + migrationState, + }); + const priorityLabelPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, @@ -1069,20 +1010,16 @@ const migrate: MigrationFunction = async ({ }, ); - const snoozedByLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Snoozed By", - description: "The user who snoozed the issue.", - properties: [], - }, - webShortname: "linear", - migrationState, + const snoozedByLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Snoozed By", + description: "The user who snoozed the issue.", + properties: [], }, - ); + webShortname: "linear", + migrationState, + }); const snoozedUntilAtPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -1098,35 +1035,25 @@ const migrate: MigrationFunction = async ({ }, ); - const sortOrderPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Sort Order", - description: - "The order of the item in relation to other items in the organization.", - possibleValues: [{ primitiveDataType: "number" }], - }, - webShortname: "linear", - migrationState, + const sortOrderPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Sort Order", + description: "The order of the item in relation to other items in the organization.", + possibleValues: [{ primitiveDataType: "number" }], }, - ); + webShortname: "linear", + migrationState, + }); - const startedAtPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Started At", - description: - "The time at which the issue was moved into started state.", - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "linear", - migrationState, + const startedAtPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Started At", + description: "The time at which the issue was moved into started state.", + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); const startedTriageAtPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -1142,23 +1069,21 @@ const migrate: MigrationFunction = async ({ }, ); - const stateLinkEntityType = await createSystemEntityTypeIfNotExists( + const stateLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "State", + description: "The workflow state that the issue is associated with.", + properties: [], + }, + webShortname: "linear", + migrationState, + }); + + const subIssueSortOrderPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "State", - description: "The workflow state that the issue is associated with.", - properties: [], - }, - webShortname: "linear", - migrationState, - }, - ); - - const subIssueSortOrderPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { propertyTypeDefinition: { title: "Sub Issue Sort Order", description: @@ -1167,7 +1092,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "linear", migrationState, - }); + }, + ); const hasSubscriberLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -1184,223 +1110,202 @@ const migrate: MigrationFunction = async ({ }, ); - const titlePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Title", - description: "The issue's title.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, + const titlePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Title", + description: "The issue's title.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "linear", + migrationState, + }); - const trashedPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Trashed", - description: - "A flag that indicates whether the issue is in the trash bin.", - possibleValues: [{ primitiveDataType: "boolean" }], - }, - webShortname: "linear", - migrationState, + const trashedPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Trashed", + description: "A flag that indicates whether the issue is in the trash bin.", + possibleValues: [{ primitiveDataType: "boolean" }], }, - ); + webShortname: "linear", + migrationState, + }); - const triagedAtPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Triaged At", - description: "The time at which the issue left triage.", - possibleValues: [{ dataTypeId: dateTimeDataTypeId }], - }, - webShortname: "linear", - migrationState, + const triagedAtPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Triaged At", + description: "The time at which the issue left triage.", + possibleValues: [{ dataTypeId: dateTimeDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); - const issueUrlPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Issue URL", - description: "The URL of the issue.", - possibleValues: [{ dataTypeId: uriDataTypeId }], - }, - webShortname: "linear", - migrationState, + const issueUrlPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Issue URL", + description: "The URL of the issue.", + possibleValues: [{ dataTypeId: uriDataTypeId }], }, - ); + webShortname: "linear", + migrationState, + }); - const linearIssueEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Issue", - description: "An issue.", - properties: [ - { - propertyType: archivedAtPropertyType, - }, - { - propertyType: autoArchivedAtPropertyType, - }, - { - propertyType: autoClosedAtPropertyType, - }, - { - propertyType: branchNamePropertyType, - required: true, - }, - { - propertyType: canceledAtPropertyType, - }, - { - propertyType: completedAtPropertyType, - }, - { - propertyType: createdAtPropertyType, - required: true, - }, - { - propertyType: customerTicketCountPropertyType, - required: true, - }, - { - propertyType: markdownDescriptionPropertyType, - }, - { - propertyType: dueDatePropertyType, - }, - { - propertyType: estimatePropertyType, - }, - { - propertyType: idPropertyType, - required: true, - }, - { - propertyType: identifierPropertyType, - required: true, - }, - { - propertyType: integrationSourceTypePropertyType, - }, - { - propertyType: issueNumberPropertyType, - required: true, - }, - { - propertyType: previousIdentifierPropertyType, - required: true, - array: true, - }, - { - propertyType: priorityPropertyType, - required: true, - }, - { - propertyType: priorityLabelPropertyType, - required: true, - }, - { - propertyType: snoozedUntilAtPropertyType, - }, - { - propertyType: sortOrderPropertyType, - required: true, - }, - { - propertyType: startedAtPropertyType, - }, - { - propertyType: startedTriageAtPropertyType, - }, - { - propertyType: subIssueSortOrderPropertyType, - }, - { - propertyType: titlePropertyType, - required: true, - }, - { - propertyType: trashedPropertyType, - }, - { - propertyType: triagedAtPropertyType, - }, - { - propertyType: updatedAtPropertyType, - required: true, - }, - { - propertyType: issueUrlPropertyType, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasAssigneeLinkEntityType, - maxItems: 1, - destinationEntityTypes: [linearUserEntityType], - }, - { - linkEntityType: hasCreatorLinkEntityType, - maxItems: 1, - destinationEntityTypes: [linearUserEntityType], - }, - /** @todo: add linked comments */ - /** @todo: cycles */ - // { - // linkEntityType: associatedWithCycleLinkEntityType, - // maxItems: 1, - // destinationEntityTypes: [linearCycleEntityType], - // }, - /** @todo: external user creator [ALPHA] */ - /** @todo: favorite */ - /** @todo: history (do we even need this?) */ - /** @todo: inverse relations */ - /** @todo: last applied template */ - { - linkEntityType: parentLinkEntityType, - maxItems: 1, - destinationEntityTypes: ["SELF_REFERENCE"], - }, - /** @todo: project */ - /** @todo: project milestone */ - /** @todo: relations */ - { - linkEntityType: snoozedByLinkEntityType, - maxItems: 1, - destinationEntityTypes: [linearUserEntityType], - }, - { - linkEntityType: stateLinkEntityType, - minItems: 1, - maxItems: 1, - destinationEntityTypes: [workflowStateEntityType], - }, - { - linkEntityType: hasSubscriberLinkEntityType, - destinationEntityTypes: [linearUserEntityType], - }, - /** @todo: team */ - ], - }, - webShortname: "linear", - migrationState, - }, - ); + const linearIssueEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Issue", + description: "An issue.", + properties: [ + { + propertyType: archivedAtPropertyType, + }, + { + propertyType: autoArchivedAtPropertyType, + }, + { + propertyType: autoClosedAtPropertyType, + }, + { + propertyType: branchNamePropertyType, + required: true, + }, + { + propertyType: canceledAtPropertyType, + }, + { + propertyType: completedAtPropertyType, + }, + { + propertyType: createdAtPropertyType, + required: true, + }, + { + propertyType: customerTicketCountPropertyType, + required: true, + }, + { + propertyType: markdownDescriptionPropertyType, + }, + { + propertyType: dueDatePropertyType, + }, + { + propertyType: estimatePropertyType, + }, + { + propertyType: idPropertyType, + required: true, + }, + { + propertyType: identifierPropertyType, + required: true, + }, + { + propertyType: integrationSourceTypePropertyType, + }, + { + propertyType: issueNumberPropertyType, + required: true, + }, + { + propertyType: previousIdentifierPropertyType, + required: true, + array: true, + }, + { + propertyType: priorityPropertyType, + required: true, + }, + { + propertyType: priorityLabelPropertyType, + required: true, + }, + { + propertyType: snoozedUntilAtPropertyType, + }, + { + propertyType: sortOrderPropertyType, + required: true, + }, + { + propertyType: startedAtPropertyType, + }, + { + propertyType: startedTriageAtPropertyType, + }, + { + propertyType: subIssueSortOrderPropertyType, + }, + { + propertyType: titlePropertyType, + required: true, + }, + { + propertyType: trashedPropertyType, + }, + { + propertyType: triagedAtPropertyType, + }, + { + propertyType: updatedAtPropertyType, + required: true, + }, + { + propertyType: issueUrlPropertyType, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasAssigneeLinkEntityType, + maxItems: 1, + destinationEntityTypes: [linearUserEntityType], + }, + { + linkEntityType: hasCreatorLinkEntityType, + maxItems: 1, + destinationEntityTypes: [linearUserEntityType], + }, + /** @todo: add linked comments */ + /** @todo: cycles */ + // { + // linkEntityType: associatedWithCycleLinkEntityType, + // maxItems: 1, + // destinationEntityTypes: [linearCycleEntityType], + // }, + /** @todo: external user creator [ALPHA] */ + /** @todo: favorite */ + /** @todo: history (do we even need this?) */ + /** @todo: inverse relations */ + /** @todo: last applied template */ + { + linkEntityType: parentLinkEntityType, + maxItems: 1, + destinationEntityTypes: ["SELF_REFERENCE"], + }, + /** @todo: project */ + /** @todo: project milestone */ + /** @todo: relations */ + { + linkEntityType: snoozedByLinkEntityType, + maxItems: 1, + destinationEntityTypes: [linearUserEntityType], + }, + { + linkEntityType: stateLinkEntityType, + minItems: 1, + maxItems: 1, + destinationEntityTypes: [workflowStateEntityType], + }, + { + linkEntityType: hasSubscriberLinkEntityType, + destinationEntityTypes: [linearUserEntityType], + }, + /** @todo: team */ + ], + }, + webShortname: "linear", + migrationState, + }); /** Linear Attachment entity type */ @@ -1433,34 +1338,25 @@ const migrate: MigrationFunction = async ({ }, ); - const metadataPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Metadata", - description: "Custom metadata related to the attachment.", - possibleValues: [{ primitiveDataType: "object" }], - }, - webShortname: "linear", - migrationState, + const metadataPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Metadata", + description: "Custom metadata related to the attachment.", + possibleValues: [{ primitiveDataType: "object" }], }, - ); + webShortname: "linear", + migrationState, + }); - const sourcePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Source", - description: - "Information about the source which created the attachment.", - possibleValues: [{ primitiveDataType: "object" }], - }, - webShortname: "linear", - migrationState, + const sourcePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Source", + description: "Information about the source which created the attachment.", + possibleValues: [{ primitiveDataType: "object" }], }, - ); + webShortname: "linear", + migrationState, + }); const sourceTypePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -1477,20 +1373,15 @@ const migrate: MigrationFunction = async ({ }, ); - const subtitlePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Subtitle", - description: - "Content for the subtitle line in the Linear attachment widget.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "linear", - migrationState, + const subtitlePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Subtitle", + description: "Content for the subtitle line in the Linear attachment widget.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "linear", + migrationState, + }); const attachmentUrlPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -1498,8 +1389,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Attachment URL", - description: - "Location of the attachment which is also used as an identifier.", + description: "Location of the attachment which is also used as an identifier.", possibleValues: [{ dataTypeId: uriDataTypeId }], }, webShortname: "linear", diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/004-create-machines-update-users.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/004-create-machines-update-users.migration.ts index 3cc357d80c7..e027a55cf5c 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/004-create-machines-update-users.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/004-create-machines-update-users.migration.ts @@ -16,34 +16,27 @@ import { import type { MigrationFunction } from "../types"; import type { EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1. Create the Actor entity type, which User and Machine will inherit from */ - const actorEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Actor", - description: - "Someone or something that can perform actions in the system", - icon: "/icons/types/user.svg", - }, - webShortname: "h", - migrationState, + const actorEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Actor", + description: "Someone or something that can perform actions in the system", + icon: "/icons/types/user.svg", }, - ); + webShortname: "h", + migrationState, + }); /** * Step 2: Create the Machine entity type */ - const machineIdentifierPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const machineIdentifierPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Machine Identifier", description: "A unique identifier for a machine", @@ -51,7 +44,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); await createSystemEntityTypeIfNotExists(context, authentication, { entityTypeDefinition: { @@ -83,19 +77,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const userEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentUserEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const userEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentUserEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!userEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentUserEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentUserEntityTypeId}`); } const newUserEntityTypeSchema = { @@ -103,41 +91,36 @@ const migrate: MigrationFunction = async ({ allOf: atLeastOne([{ $ref: actorEntityType.schema.$id }]), }; - const { updatedEntityTypeId: updatedUserEntityTypeId } = - await updateSystemEntityType(context, authentication, { - currentEntityTypeId: currentUserEntityTypeId, - migrationState, - newSchema: newUserEntityTypeSchema, - }); - - /** Step 4: Update the Occurred in Entity link type to have an Entity Edition Id property, to track which edition was created */ - const editionIdPropertyType = await createSystemPropertyTypeIfNotExists( + const { updatedEntityTypeId: updatedUserEntityTypeId } = await updateSystemEntityType( context, authentication, { - propertyTypeDefinition: { - title: "Entity Edition Id", - description: "An identifier for an edition of an entity", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", + currentEntityTypeId: currentUserEntityTypeId, migrationState, + newSchema: newUserEntityTypeSchema, }, ); + /** Step 4: Update the Occurred in Entity link type to have an Entity Edition Id property, to track which edition was created */ + const editionIdPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Entity Edition Id", + description: "An identifier for an edition of an entity", + possibleValues: [{ primitiveDataType: "text" }], + }, + webShortname: "h", + migrationState, + }); + const currentOccurredInEntityEntityTypeId = getCurrentHashLinkEntityTypeId({ linkEntityTypeKey: "occurredInEntity", migrationState, }); - const occurredInEntityEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentOccurredInEntityEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const occurredInEntityEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentOccurredInEntityEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!occurredInEntityEntityType) { throw new NotFoundError( @@ -155,12 +138,15 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId: updatedOccurredInEntityEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedOccurredInEntityEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentOccurredInEntityEntityTypeId, migrationState, newSchema: newOccurredInEntityEntityTypeSchema, - }); + }, + ); /** Step 5: Create a new Graph Change notification type to notify of generic CRUD operations in the graph */ @@ -175,8 +161,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Graph Change Type", - description: - "The type of change that occurred (e.g. create, update, archive)", + description: "The type of change that occurred (e.g. create, update, archive)", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "h", @@ -210,10 +195,7 @@ const migrate: MigrationFunction = async ({ /** Step 6: Update the dependencies of entity types which we've updated above */ await upgradeDependenciesInHashEntityType(context, authentication, { - upgradedEntityTypeIds: [ - updatedUserEntityTypeId, - updatedOccurredInEntityEntityTypeId, - ], + upgradedEntityTypeIds: [updatedUserEntityTypeId, updatedOccurredInEntityEntityTypeId], dependentEntityTypeKeys: [ "comment", "commentNotification", diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/005-create-hash-system-entities-and-web-bots.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/005-create-hash-system-entities-and-web-bots.migration.ts index 567ac5d516b..93e0644b4c4 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/005-create-hash-system-entities-and-web-bots.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/005-create-hash-system-entities-and-web-bots.migration.ts @@ -10,22 +10,12 @@ import { import { logger } from "../../../../logger"; import { createHashInstance } from "../../../knowledge/system-types/hash-instance"; import { systemAccountId } from "../../../system-account"; -import { - ensureSystemWebEntitiesExist, - owningWebs, -} from "../../system-webs-and-entities"; -import { - getCurrentHashSystemEntityTypeId, - getExistingUsersAndOrgs, -} from "../util"; +import { ensureSystemWebEntitiesExist, owningWebs } from "../../system-webs-and-entities"; +import { getCurrentHashSystemEntityTypeId, getExistingUsersAndOrgs } from "../util"; import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - authentication, - context, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ authentication, context, migrationState }) => { /** * This migration creates entities that are required in later migration scripts. * Other system entities (belonging to non-hash webs) are created in {@link ensureSystemEntitiesExist} @@ -90,16 +80,10 @@ const migrate: MigrationFunction = async ({ * This step is only required to transition instances existing prior to Dec 2023, and can be deleted once they have been migrated. */ - const { users, orgs } = await getExistingUsersAndOrgs( - context, - authentication, - {}, - ); + const { users, orgs } = await getExistingUsersAndOrgs(context, authentication, {}); for (const principal of users.concat(orgs)) { - const webId = extractWebIdFromEntityId( - principal.metadata.recordId.entityId, - ); + const webId = extractWebIdFromEntityId(principal.metadata.recordId.entityId); const webMachine = await getWebMachineEntity(context, authentication, { webId, }); diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/007-create-api-usage-tracking.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/007-create-api-usage-tracking.migration.ts index 6389b0bd3f6..013b13b61f6 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/007-create-api-usage-tracking.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/007-create-api-usage-tracking.migration.ts @@ -15,11 +15,7 @@ import type { MigrationFunction } from "../types"; import type { Entity } from "@blockprotocol/type-system"; import type { ServiceFeature } from "@local/hash-isomorphic-utils/system-types/shared"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** Step 1: Create an entity type that describes a chargeable service */ const serviceNamePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -110,39 +106,33 @@ const migrate: MigrationFunction = async ({ }, ); - const serviceUnitCost = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Service Unit Cost", - description: "The unit cost of a service", - possibleValues: [ - { - propertyTypeObjectProperties: { - [inputUnitCostPropertyType.metadata.recordId.baseUrl]: { - $ref: inputUnitCostPropertyType.schema.$id, - }, - [outputUnitCostPropertyType.metadata.recordId.baseUrl]: { - $ref: outputUnitCostPropertyType.schema.$id, - }, - [appliesFromPropertyType.metadata.recordId.baseUrl]: { - $ref: appliesFromPropertyType.schema.$id, - }, - [appliesUntilPropertyType.metadata.recordId.baseUrl]: { - $ref: appliesUntilPropertyType.schema.$id, - }, + const serviceUnitCost = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Service Unit Cost", + description: "The unit cost of a service", + possibleValues: [ + { + propertyTypeObjectProperties: { + [inputUnitCostPropertyType.metadata.recordId.baseUrl]: { + $ref: inputUnitCostPropertyType.schema.$id, + }, + [outputUnitCostPropertyType.metadata.recordId.baseUrl]: { + $ref: outputUnitCostPropertyType.schema.$id, + }, + [appliesFromPropertyType.metadata.recordId.baseUrl]: { + $ref: appliesFromPropertyType.schema.$id, + }, + [appliesUntilPropertyType.metadata.recordId.baseUrl]: { + $ref: appliesUntilPropertyType.schema.$id, }, - propertyTypeObjectRequiredProperties: [ - appliesFromPropertyType.metadata.recordId.baseUrl, - ], }, - ], - }, - webShortname: "h", - migrationState, + propertyTypeObjectRequiredProperties: [appliesFromPropertyType.metadata.recordId.baseUrl], + }, + ], }, - ); + webShortname: "h", + migrationState, + }); const serviceFeatureEntityType = await createSystemEntityTypeIfNotExists( context, @@ -193,39 +183,31 @@ const migrate: MigrationFunction = async ({ }, ); - const createdLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Created", - inverse: { - title: "Created By", - }, - description: "The thing that something created.", + const createdLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Created", + inverse: { + title: "Created By", }, - webShortname: "h", - migrationState, + description: "The thing that something created.", }, - ); + webShortname: "h", + migrationState, + }); - const updatedLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Updated", - inverse: { - title: "Updated By", - }, - description: "The thing that something created.", + const updatedLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Updated", + inverse: { + title: "Updated By", }, - webShortname: "h", - migrationState, + description: "The thing that something created.", }, - ); + webShortname: "h", + migrationState, + }); const inputUnitCountPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -360,39 +342,21 @@ const migrate: MigrationFunction = async ({ shortname: "h", }); if (!hashOrg) { - throw new Error( - "Org with shortname 'h' does not exist by migration 007, but it should.", - ); + throw new Error("Org with shortname 'h' does not exist by migration 007, but it should."); } const hashWebId = hashOrg.webId; - const existingServiceFeatureEntities = (await getEntitiesByType( - context, - authentication, - { - entityTypeId: serviceFeatureEntityType.schema.$id, - }, - )) as Entity[]; + const existingServiceFeatureEntities = (await getEntitiesByType(context, authentication, { + entityTypeId: serviceFeatureEntityType.schema.$id, + })) as Entity[]; - for (const { - serviceName, - featureName, - inputUnitCost, - outputUnitCost, - } of initialServices) { - const existingServiceFeatureEntity = existingServiceFeatureEntities.find( - (entity) => { - const { - serviceName: serviceNameProperty, - featureName: featureNameProperty, - } = simplifyProperties(entity.properties); + for (const { serviceName, featureName, inputUnitCost, outputUnitCost } of initialServices) { + const existingServiceFeatureEntity = existingServiceFeatureEntities.find((entity) => { + const { serviceName: serviceNameProperty, featureName: featureNameProperty } = + simplifyProperties(entity.properties); - return ( - serviceNameProperty === serviceName && - featureNameProperty === featureName - ); - }, - ); + return serviceNameProperty === serviceName && featureNameProperty === featureName; + }); if (existingServiceFeatureEntity) { logger.debug( @@ -401,28 +365,22 @@ const migrate: MigrationFunction = async ({ continue; } - logger.info( - `Creating service feature entity for ${serviceName}:${featureName}`, - ); + logger.info(`Creating service feature entity for ${serviceName}:${featureName}`); await createEntity(context, authentication, { - entityTypeIds: [ - serviceFeatureEntityType.schema.$id, - ] as ServiceFeature["entityTypeIds"], + entityTypeIds: [serviceFeatureEntityType.schema.$id] as ServiceFeature["entityTypeIds"], properties: { value: { "https://hash.ai/@h/types/property-type/service-name/": { value: serviceName, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/feature-name/": { value: featureName, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/service-unit-cost/": { @@ -446,8 +404,7 @@ const migrate: MigrationFunction = async ({ "https://hash.ai/@h/types/property-type/applies-from/": { value: new Date("2023-12-20").toISOString(), metadata: { - dataTypeId: - "https://hash.ai/@h/types/data-type/datetime/v/1", + dataTypeId: "https://hash.ai/@h/types/data-type/datetime/v/1", }, }, }, diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/008-create-plugin-settings-update-users.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/008-create-plugin-settings-update-users.migration.ts index 8b8175c43ef..cf9f5f537a7 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/008-create-plugin-settings-update-users.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/008-create-plugin-settings-update-users.migration.ts @@ -18,16 +18,14 @@ import { import type { MigrationFunction } from "../types"; import type { BaseUrl, EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1. Create the Browser Plugin Settings entity type */ - const manualInferenceConfigurationPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const manualInferenceConfigurationPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Manual Inference Configuration", description: "Configuration for a manual entity inference feature", @@ -35,50 +33,47 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); - - const automaticInferenceConfigurationPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Automatic Inference Configuration", - description: - "Configuration for an automatic or passive entity inference feature", - possibleValues: [{ primitiveDataType: "object" }], - }, - webShortname: "h", - migrationState, - }); + }, + ); - const popupTabPropertyType = await createSystemPropertyTypeIfNotExists( + const automaticInferenceConfigurationPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "Browser Plugin Tab", - description: "A tab in the HASH browser plugin", - possibleValues: [{ primitiveDataType: "text" }], + title: "Automatic Inference Configuration", + description: "Configuration for an automatic or passive entity inference feature", + possibleValues: [{ primitiveDataType: "object" }], }, webShortname: "h", migrationState, }, ); - const draftNotePropertyType = await createSystemPropertyTypeIfNotExists( + const popupTabPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Browser Plugin Tab", + description: "A tab in the HASH browser plugin", + possibleValues: [{ primitiveDataType: "text" }], + }, + webShortname: "h", + migrationState, + }); + + const draftNotePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Draft Note", + description: "A working draft of a text note", + possibleValues: [{ primitiveDataType: "text" }], + }, + webShortname: "h", + migrationState, + }); + + const browserPluginSettingsEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { - propertyTypeDefinition: { - title: "Draft Note", - description: "A working draft of a text note", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, - }, - ); - - const browserPluginSettingsEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { entityTypeDefinition: { title: "Browser Plugin Settings", titlePlural: "Browser Plugin Settings", @@ -104,24 +99,21 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); /** * Step 2: Create the 'has' link */ - const hasLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has", - description: "Something that something has", - }, - webShortname: "h", - migrationState, + const hasLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has", + description: "Something that something has", }, - ); + webShortname: "h", + migrationState, + }); /** Step 3: Update the User entity type to link to the Browser Plugin Settings entity type */ const currentUserEntityTypeId = getCurrentHashSystemEntityTypeId({ @@ -129,19 +121,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const userEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentUserEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const userEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentUserEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!userEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentUserEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentUserEntityTypeId}`); } const newUserEntityTypeSchema: EntityType = { @@ -157,12 +143,15 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId: updatedUserEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedUserEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentUserEntityTypeId, migrationState, newSchema: newUserEntityTypeSchema, - }); + }, + ); /** Step 4: Update the dependencies of entity types which we've updated above */ await upgradeDependenciesInHashEntityType(context, authentication, { diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/009-add-upload-completed-at-property-type.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/009-add-upload-completed-at-property-type.migration.ts index 2ad8199266f..c35fc97dc55 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/009-add-upload-completed-at-property-type.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/009-add-upload-completed-at-property-type.migration.ts @@ -16,11 +16,7 @@ import { import type { MigrationFunction } from "../types"; import type { BaseUrl, EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** Step 1: Create the upload completed at */ const dateTimeDataTypeId = getCurrentHashDataTypeId({ @@ -28,8 +24,10 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const uploadCompletedAtPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const uploadCompletedAtPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Upload Completed At", description: "The timestamp when the upload of something has completed", @@ -37,7 +35,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); /** Step 2: Add the property to the file entity type */ @@ -46,19 +45,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const fileEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentFileEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const fileEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentFileEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!fileEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentFileEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentFileEntityTypeId}`); } const newFileEntityTypeSchema: EntityType = { @@ -71,12 +64,15 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId: updatedFileEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedFileEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentFileEntityTypeId, migrationState, newSchema: newFileEntityTypeSchema, - }); + }, + ); /** Step 3: Update the dependencies of entity types which we've updated above */ await upgradeDependenciesInHashEntityType(context, authentication, { diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/010-create-office-file-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/010-create-office-file-types.migration.ts index 29092698268..97c9824119c 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/010-create-office-file-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/010-create-office-file-types.migration.ts @@ -1,15 +1,8 @@ -import { - createSystemEntityTypeIfNotExists, - getCurrentHashSystemEntityTypeId, -} from "../util"; +import { createSystemEntityTypeIfNotExists, getCurrentHashSystemEntityTypeId } from "../util"; import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1. Create the `Document File` entity type and its child entity types. */ @@ -19,103 +12,83 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const documentFileEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [currentFileEntityTypeId], - title: "Document File", - titlePlural: "Document Files", - icon: "/icons/types/file-lines.svg", - description: "A document file.", - properties: [ - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/v/2", - required: false, - }, - ], - }, - webShortname: "h", - migrationState, + const documentFileEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [currentFileEntityTypeId], + title: "Document File", + titlePlural: "Document Files", + icon: "/icons/types/file-lines.svg", + description: "A document file.", + properties: [ + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/v/2", + required: false, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); - const _pdfFileEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [documentFileEntityType.schema.$id], - title: "PDF Document", - titlePlural: "PDF Documents", - icon: "/icons/types/file-pdf.svg", - description: "A PDF document.", - }, - webShortname: "h", - migrationState, + const _pdfFileEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [documentFileEntityType.schema.$id], + title: "PDF Document", + titlePlural: "PDF Documents", + icon: "/icons/types/file-pdf.svg", + description: "A PDF document.", }, - ); + webShortname: "h", + migrationState, + }); - const _docxFileEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [documentFileEntityType.schema.$id], - title: "DOCX Document", - titlePlural: "DOCX Documents", - icon: "/icons/types/file-word.svg", - description: "A Microsoft Word document.", - }, - webShortname: "h", - migrationState, + const _docxFileEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [documentFileEntityType.schema.$id], + title: "DOCX Document", + titlePlural: "DOCX Documents", + icon: "/icons/types/file-word.svg", + description: "A Microsoft Word document.", }, - ); + webShortname: "h", + migrationState, + }); /** * Step 2. Create the `Presentation File` entity type and its child entity types. */ - const slideshowFileEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [currentFileEntityTypeId], - title: "Presentation File", - titlePlural: "Presentation Files", - icon: "/icons/types/presentation-screen.svg", - description: "A presentation file.", - properties: [ - { - propertyType: - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/v/2", - required: false, - }, - ], - }, - webShortname: "h", - migrationState, + const slideshowFileEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [currentFileEntityTypeId], + title: "Presentation File", + titlePlural: "Presentation Files", + icon: "/icons/types/presentation-screen.svg", + description: "A presentation file.", + properties: [ + { + propertyType: + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/v/2", + required: false, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); - const _pptxFileEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [slideshowFileEntityType.schema.$id], - title: "PPTX Presentation", - titlePlural: "PPTX Presentations", - icon: "/icons/types/file-powerpoint.svg", - description: "A Microsoft PowerPoint presentation.", - }, - webShortname: "h", - migrationState, + const _pptxFileEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [slideshowFileEntityType.schema.$id], + title: "PPTX Presentation", + titlePlural: "PPTX Presentations", + icon: "/icons/types/file-powerpoint.svg", + description: "A Microsoft PowerPoint presentation.", }, - ); + webShortname: "h", + migrationState, + }); return migrationState; }; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/011-deprecate-preferred-name.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/011-deprecate-preferred-name.migration.ts index 7e42170674c..ecaac73c7ba 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/011-deprecate-preferred-name.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/011-deprecate-preferred-name.migration.ts @@ -18,11 +18,7 @@ import { upgradeEntityTypeDependencies } from "../util/upgrade-entity-type-depen import type { MigrationFunction } from "../types"; import type { BaseUrl, EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1. Update the `Actor` entity type to define the `displayName` property type */ @@ -32,25 +28,17 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const actorEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentActorEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const actorEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentActorEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!actorEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentActorEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentActorEntityTypeId}`); } - const { - propertyTypeId: displayNamePropertyTypeId, - propertyTypeBaseUrl: displayNameBaseUrl, - } = blockProtocolPropertyTypes.displayName; + const { propertyTypeId: displayNamePropertyTypeId, propertyTypeBaseUrl: displayNameBaseUrl } = + blockProtocolPropertyTypes.displayName; const newActorEntityTypeSchema: EntityType = { ...actorEntityType.schema, @@ -63,12 +51,15 @@ const migrate: MigrationFunction = async ({ labelProperty: displayNameBaseUrl, }; - const { updatedEntityTypeId: updatedActorEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedActorEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentActorEntityTypeId, migrationState, newSchema: newActorEntityTypeSchema, - }); + }, + ); /** * Step 2. Update `Machine` to inherit from the latest version of `Actor` @@ -111,19 +102,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const userEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentUserEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const userEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentUserEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!userEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentUserEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentUserEntityTypeId}`); } const newUserEntityTypeSchema: EntityType = { @@ -141,10 +126,7 @@ const migrate: MigrationFunction = async ({ }), properties: Object.entries(userEntityType.schema.properties).reduce( (prev, [propertyTypeBaseUrl, value]) => { - if ( - propertyTypeBaseUrl === - systemPropertyTypes.preferredName.propertyTypeBaseUrl - ) { + if (propertyTypeBaseUrl === systemPropertyTypes.preferredName.propertyTypeBaseUrl) { return prev; } else { return { @@ -157,12 +139,15 @@ const migrate: MigrationFunction = async ({ ), }; - const { updatedEntityTypeId: updatedUserEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedUserEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentUserEntityTypeId, migrationState, newSchema: newUserEntityTypeSchema, - }); + }, + ); /** * Step 5: Update entity types that reference the `User` entity type @@ -214,8 +199,7 @@ const migrate: MigrationFunction = async ({ migrateProperties: { [systemEntityTypes.user.entityTypeBaseUrl]: (previousUserProperties) => { const { - [systemPropertyTypes.preferredName.propertyTypeBaseUrl]: - previousPreferredName, + [systemPropertyTypes.preferredName.propertyTypeBaseUrl]: previousPreferredName, ...remainingProperties } = previousUserProperties.value; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/012-create-google-sheets-system-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/012-create-google-sheets-system-types.migration.ts index 9e2eecd4026..c4ffbf26a5c 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/012-create-google-sheets-system-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/012-create-google-sheets-system-types.migration.ts @@ -16,11 +16,7 @@ import { import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { if (!enabledIntegrations.googleSheets) { return migrationState; } @@ -42,62 +38,56 @@ const migrate: MigrationFunction = async ({ entityTypeKey: "userSecret", }); - const accountIdPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Account Id", - description: "A unique identifier for a Google account.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "google", - migrationState, + const accountIdPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Account Id", + description: "A unique identifier for a Google account.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "google", + migrationState, + }); - const googleAccountEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Account", - titlePlural: "Accounts", - icon: "/icons/types/google.svg", - description: "A Google user account.", - properties: [ - { - propertyType: accountIdPropertyType, - required: true, - }, - { - propertyType: emailPropertyType, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.displayName.propertyTypeId, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: usesUserSecretLinkEntityType, - destinationEntityTypes: [userSecretEntityType], - minItems: 0, - maxItems: 1, - }, - ], - }, - webShortname: "google", - migrationState, + const googleAccountEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Account", + titlePlural: "Accounts", + icon: "/icons/types/google.svg", + description: "A Google user account.", + properties: [ + { + propertyType: accountIdPropertyType, + required: true, + }, + { + propertyType: emailPropertyType, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.displayName.propertyTypeId, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: usesUserSecretLinkEntityType, + destinationEntityTypes: [userSecretEntityType], + minItems: 0, + maxItems: 1, + }, + ], }, - ); + webShortname: "google", + migrationState, + }); /** * Create a Google Sheets File entity type. */ - const associatedWithAccountLinkEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const associatedWithAccountLinkEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [blockProtocolEntityTypes.link.entityTypeId], title: "Associated With Account", @@ -109,39 +99,31 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); - - const fileIdPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "File Id", - description: "A system identifier for a file.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, }, ); - const actorTypeDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "Actor Type", - description: - "The type of thing that can, should or will act on something.", - enum: ["user", "machine"], - type: "string", - }, - conversions: {}, - webShortname: "h", - migrationState, + const fileIdPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "File Id", + description: "A system identifier for a file.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); + + const actorTypeDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "Actor Type", + description: "The type of thing that can, should or will act on something.", + enum: ["user", "machine"], + type: "string", + }, + conversions: {}, + webShortname: "h", + migrationState, + }); const dataAudiencePropertyType = await createSystemPropertyTypeIfNotExists( context, diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/013-add-enabled-feature-flags-property.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/013-add-enabled-feature-flags-property.migration.ts index eac96fbfb7d..7c96fb89b6e 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/013-add-enabled-feature-flags-property.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/013-add-enabled-feature-flags-property.migration.ts @@ -15,26 +15,24 @@ import { import type { MigrationFunction } from "../types"; import type { BaseUrl, EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1. Create the `enabledFeatureFlags` property type */ - const enabledFeatureFlagsPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const enabledFeatureFlagsPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Enabled Feature Flags", - description: - "A list of identifiers for a feature flags that are enabled.", + description: "A list of identifiers for a feature flags that are enabled.", possibleValues: [{ primitiveDataType: "text", array: true }], }, webShortname: "h", migrationState, - }); + }, + ); /** * Step 2: Add the `enabledFeatureFlags` property type to the `User` entity type @@ -45,19 +43,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const userEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentUserEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const userEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentUserEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!userEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentUserEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentUserEntityTypeId}`); } const newUserEntityTypeSchema: EntityType = { @@ -70,12 +62,15 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId: updatedUserEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedUserEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentUserEntityTypeId, migrationState, newSchema: newUserEntityTypeSchema, - }); + }, + ); /** * Step 4: Update the dependencies of the `User` entity type diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/017-add-use-case-form-and-example-org.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/017-add-use-case-form-and-example-org.migration.ts index f83ac3421f0..fc56933387e 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/017-add-use-case-form-and-example-org.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/017-add-use-case-form-and-example-org.migration.ts @@ -5,10 +5,7 @@ import { } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { logger } from "../../../../logger"; -import { - createOrg, - getOrgByShortname, -} from "../../../knowledge/system-types/org"; +import { createOrg, getOrgByShortname } from "../../../knowledge/system-types/org"; import { createSystemEntityTypeIfNotExists, createSystemPropertyTypeIfNotExists, @@ -17,11 +14,7 @@ import { import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { if (isSelfHostedInstance) { /** * Functionality is only relevant to hosted HASH, i.e. the instance at https://[app].hash.ai @@ -33,19 +26,15 @@ const migrate: MigrationFunction = async ({ * Create the entity type to hold information about a user's potential use(s) of HASH */ - const rolePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Role", - description: "The name of someone or something's role.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const rolePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Role", + description: "The name of someone or something's role.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); const intendedUsePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -53,8 +42,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Intended Use", - description: - "The name or description of someone's intended use of something", + description: "The name or description of someone's intended use of something", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "h", @@ -68,8 +56,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Current Approach", - description: - "The name or description of the current approach to something", + description: "The name or description of the current approach to something", possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "h", @@ -91,14 +78,15 @@ const migrate: MigrationFunction = async ({ }, ); - const _prospectiveUserDefinitionEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const _prospectiveUserDefinitionEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { title: "Prospective User", titlePlural: "Prospective Users", icon: "/icons/types/user-plus.svg", - description: - "Information about a prospective user of an application or system", + description: "Information about a prospective user of an application or system", labelProperty: systemPropertyTypes.email.propertyTypeBaseUrl, properties: [ { @@ -135,7 +123,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); /** * Create an `@example` org @@ -150,13 +139,9 @@ const migrate: MigrationFunction = async ({ name: "Example", websiteUrl: "https://example.com", orgEntityTypeVersion: - migrationState.entityTypeVersions[ - systemEntityTypes.organization.entityTypeBaseUrl - ], + migrationState.entityTypeVersions[systemEntityTypes.organization.entityTypeBaseUrl], machineEntityTypeVersion: - migrationState.entityTypeVersions[ - systemEntityTypes.machine.entityTypeBaseUrl - ], + migrationState.entityTypeVersions[systemEntityTypes.machine.entityTypeBaseUrl], }); logger.info("Created @example org"); } diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/018-add-application-preferences-property.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/018-add-application-preferences-property.migration.ts index 974a44f6d97..2562fdc7f09 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/018-add-application-preferences-property.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/018-add-application-preferences-property.migration.ts @@ -15,17 +15,15 @@ import { import type { MigrationFunction } from "../types"; import type { BaseUrl, EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1. Create the `applicationPreferences` property type */ - const applicationPreferencesPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const applicationPreferencesPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Application Preferences", description: @@ -39,7 +37,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); /** * Step 2: Add the `applicationPreferences` property type to the `User` entity type @@ -50,19 +49,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const userEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentUserEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const userEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentUserEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!userEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentUserEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentUserEntityTypeId}`); } const newUserEntityTypeSchema: EntityType = { @@ -75,12 +68,15 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId: updatedUserEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedUserEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentUserEntityTypeId, migrationState, newSchema: newUserEntityTypeSchema, - }); + }, + ); /** * Step 4: Update the dependencies of the `User` entity type diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/019-add-doc-company-and-person-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/019-add-doc-company-and-person-types.migration.ts index cf2dd480bae..f9b614ddc00 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/019-add-doc-company-and-person-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/019-add-doc-company-and-person-types.migration.ts @@ -16,156 +16,116 @@ import { import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { - const doiDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "DOI", - titlePlural: "DOIs", - description: - "A DOI (Digital Object Identifier), used to identify digital objects such as journal articles or datasets.", - type: "string", - }, - conversions: {}, - migrationState, - webShortname: "h", +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { + const doiDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "DOI", + titlePlural: "DOIs", + description: + "A DOI (Digital Object Identifier), used to identify digital objects such as journal articles or datasets.", + type: "string", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const doiPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "DOI", - description: "The Digital Object Identifier (DOI) of an object", - possibleValues: [{ dataTypeId: doiDataType.schema.$id }], - }, - migrationState, - webShortname: "h", + const doiPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "DOI", + description: "The Digital Object Identifier (DOI) of an object", + possibleValues: [{ dataTypeId: doiDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); const uriDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "uri", migrationState, }); - const doiLinkPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "DOI Link", - description: - "A permanent link for a digital object, using its Digital Object Identifier (DOI), which resolves to a webpage describing it", - possibleValues: [{ dataTypeId: uriDataTypeId }], - }, - migrationState, - webShortname: "h", + const doiLinkPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "DOI Link", + description: + "A permanent link for a digital object, using its Digital Object Identifier (DOI), which resolves to a webpage describing it", + possibleValues: [{ dataTypeId: uriDataTypeId }], }, - ); + migrationState, + webShortname: "h", + }); - const isbnDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "ISBN", - titlePlural: "ISBNs", - description: - "International Standard Book Number: a numeric commercial book identifier that is intended to be unique, issued by an affiliate of the International ISBN Agency.", - type: "string", - }, - conversions: {}, - migrationState, - webShortname: "h", + const isbnDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "ISBN", + titlePlural: "ISBNs", + description: + "International Standard Book Number: a numeric commercial book identifier that is intended to be unique, issued by an affiliate of the International ISBN Agency.", + type: "string", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const isbnPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "ISBN", - description: "The International Standard Book Number (ISBN) of a book", - possibleValues: [{ dataTypeId: isbnDataType.schema.$id }], - }, - migrationState, - webShortname: "h", + const isbnPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "ISBN", + description: "The International Standard Book Number (ISBN) of a book", + possibleValues: [{ dataTypeId: isbnDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); - const summaryPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Summary", - description: "An overview or synopsis of something.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const summaryPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Summary", + description: "An overview or synopsis of something.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); - const integerDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - title: "Integer", - description: - "The number zero (0), a positive natural number (e.g. 1, 2, 3), or the negation of a positive natural number (e.g. -1, -2, -3).", - multipleOf: 1, - type: "number", - }, - conversions: {}, - migrationState, - webShortname: "h", + const integerDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + title: "Integer", + description: + "The number zero (0), a positive natural number (e.g. 1, 2, 3), or the negation of a positive natural number (e.g. -1, -2, -3).", + multipleOf: 1, + type: "number", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const calendarYearDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: integerDataType.schema.$id }], - title: "Calendar Year", - description: "A year in the Gregorian calendar.", - type: "number", - }, - conversions: {}, - migrationState, - webShortname: "h", + const calendarYearDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: integerDataType.schema.$id }], + title: "Calendar Year", + description: "A year in the Gregorian calendar.", + type: "number", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const publicationYear = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Publication Year", - description: "The year in which something was first published.", - possibleValues: [{ dataTypeId: calendarYearDataType.schema.$id }], - }, - migrationState, - webShortname: "h", + const publicationYear = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Publication Year", + description: "The year in which something was first published.", + possibleValues: [{ dataTypeId: calendarYearDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); const methodologyPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -182,26 +142,13 @@ const migrate: MigrationFunction = async ({ }, ); - const experimentalSubjectPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Experimental Subject", - description: - "The type of participant or observed entity in an experiment or study.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", - }); - - const findingPropertyType = await createSystemPropertyTypeIfNotExists( + const experimentalSubjectPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "Finding", - description: - "The results or conclusion of an experiment, research project, investigation, etc.", + title: "Experimental Subject", + description: "The type of participant or observed entity in an experiment or study.", possibleValues: [{ primitiveDataType: "text" }], }, migrationState, @@ -209,6 +156,17 @@ const migrate: MigrationFunction = async ({ }, ); + const findingPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Finding", + description: + "The results or conclusion of an experiment, research project, investigation, etc.", + possibleValues: [{ primitiveDataType: "text" }], + }, + migrationState, + webShortname: "h", + }); + /** @todo H-3619: Infer info on publisher and link to docs */ // const _publishedByLinkEntityType = await createSystemEntityTypeIfNotExists( // context, @@ -245,48 +203,40 @@ const migrate: MigrationFunction = async ({ // }, // ); - const affiliatedWith = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], + const affiliatedWith = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Affiliated With", + inverse: { title: "Affiliated With", - inverse: { - title: "Affiliated With", - }, - description: "Something that something is affiliated with.", }, - migrationState, - webShortname: "h", + description: "Something that something is affiliated with.", }, - ); + migrationState, + webShortname: "h", + }); - const institutionEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Institution", - titlePlural: "Institutions", - icon: "/icons/types/building-columns.svg", - labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, - description: - "An organization dedicated to a specific purpose, such as education, research, or public service, and structured with formal systems of governance and operation.", - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - }, - ], - }, - migrationState, - webShortname: "h", + const institutionEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Institution", + titlePlural: "Institutions", + icon: "/icons/types/building-columns.svg", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + description: + "An organization dedicated to a specific purpose, such as education, research, or public service, and structured with formal systems of governance and operation.", + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); /** @todo H-3619: Infer info on publication venue and link to docs */ // const archiveEntityType = await createSystemEntityTypeIfNotExists( @@ -351,46 +301,42 @@ const migrate: MigrationFunction = async ({ // }, // ); - const personEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Person", - /** - * @todo when updating this, add plural title and set SVG icon - */ - icon: "👤", - /** @todo improve this desc */ - description: "A human being", - labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - }, - { - propertyType: getCurrentHashPropertyTypeId({ - propertyTypeKey: "email", - migrationState, - }), - array: true, - }, - ], - outgoingLinks: [ - { - destinationEntityTypes: [institutionEntityType.schema.$id], - linkEntityType: affiliatedWith.schema.$id, - }, - ], - }, - migrationState, - webShortname: "h", + const personEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Person", + /** + * @todo when updating this, add plural title and set SVG icon + */ + icon: "👤", + /** @todo improve this desc */ + description: "A human being", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + }, + { + propertyType: getCurrentHashPropertyTypeId({ + propertyTypeKey: "email", + migrationState, + }), + array: true, + }, + ], + outgoingLinks: [ + { + destinationEntityTypes: [institutionEntityType.schema.$id], + linkEntityType: affiliatedWith.schema.$id, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); const numberOfPagesPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -411,67 +357,59 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const docEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Doc", - description: "A written work, such as a book or article.", - icon: "/types/icons/page-lines.svg", - titlePlural: "Docs", - labelProperty: systemPropertyTypes.title.propertyTypeBaseUrl, - properties: [ - { - propertyType: getCurrentHashPropertyTypeId({ - propertyTypeKey: "title", - migrationState, - }), - required: true, - }, - { - propertyType: summaryPropertyType.schema.$id, - }, - { - propertyType: numberOfPagesPropertyType.schema.$id, - }, - { - propertyType: publicationYear.schema.$id, - }, - ], - outgoingLinks: [ - { - destinationEntityTypes: [personEntityType.schema.$id], - linkEntityType: authoredByLinkEntityTypeId, - }, - ], - }, - migrationState, - webShortname: "h", + const docEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Doc", + description: "A written work, such as a book or article.", + icon: "/types/icons/page-lines.svg", + titlePlural: "Docs", + labelProperty: systemPropertyTypes.title.propertyTypeBaseUrl, + properties: [ + { + propertyType: getCurrentHashPropertyTypeId({ + propertyTypeKey: "title", + migrationState, + }), + required: true, + }, + { + propertyType: summaryPropertyType.schema.$id, + }, + { + propertyType: numberOfPagesPropertyType.schema.$id, + }, + { + propertyType: publicationYear.schema.$id, + }, + ], + outgoingLinks: [ + { + destinationEntityTypes: [personEntityType.schema.$id], + linkEntityType: authoredByLinkEntityTypeId, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); - const _bookEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [docEntityType.schema.$id], - title: "Book", - titlePlural: "Books", - icon: "/icons/types/book.svg", - description: - "A written work, typically longer than an article, often published in print form.", - properties: [ - { - propertyType: isbnPropertyType.schema.$id, - }, - ], - }, - migrationState, - webShortname: "h", + const _bookEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [docEntityType.schema.$id], + title: "Book", + titlePlural: "Books", + icon: "/icons/types/book.svg", + description: + "A written work, typically longer than an article, often published in print form.", + properties: [ + { + propertyType: isbnPropertyType.schema.$id, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); const _academicPaperEntityType = await createSystemEntityTypeIfNotExists( context, diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/020-add-integration-parent-type.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/020-add-integration-parent-type.migration.ts index c7a196b7097..dac571369d0 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/020-add-integration-parent-type.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/020-add-integration-parent-type.migration.ts @@ -14,46 +14,33 @@ import { import type { MigrationFunction } from "../types"; import type { EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Create the integration entity type to act as a parent type for all integration types. */ - const integrationEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Integration", - description: "An integration with a third-party service.", - properties: [], - }, - migrationState, - webShortname: "h", + const integrationEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Integration", + description: "An integration with a third-party service.", + properties: [], }, - ); + migrationState, + webShortname: "h", + }); if (enabledIntegrations.linear) { /** * Add the integration entity type as a parent of the linear integration entity type. */ - const currentLinearIntegrationEntityTypeId = - getCurrentHashSystemEntityTypeId({ - entityTypeKey: "linearIntegration", - migrationState, - }); + const currentLinearIntegrationEntityTypeId = getCurrentHashSystemEntityTypeId({ + entityTypeKey: "linearIntegration", + migrationState, + }); - const linearIntegrationEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentLinearIntegrationEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const linearIntegrationEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentLinearIntegrationEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!linearIntegrationEntityType) { throw new NotFoundError( @@ -77,9 +64,7 @@ const migrate: MigrationFunction = async ({ }); await upgradeEntitiesToNewTypeVersion(context, authentication, { - entityTypeBaseUrls: [ - systemEntityTypes.linearIntegration.entityTypeBaseUrl, - ], + entityTypeBaseUrls: [systemEntityTypes.linearIntegration.entityTypeBaseUrl], migrationState, }); } diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/021-add-org-invites.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/021-add-org-invites.migration.ts index 0183d8231d0..58978047b2a 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/021-add-org-invites.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/021-add-org-invites.migration.ts @@ -18,11 +18,7 @@ import { import type { MigrationFunction } from "../types"; import type { BaseUrl, EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1: Create the 'Invitation Via Email' and 'Invitation Via Shortname' link types, * and the 'Has Issued Invitation' link type which will link these from an Organization @@ -42,24 +38,20 @@ const migrate: MigrationFunction = async ({ propertyTypeKey: "shortname", }); - const invitationEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Invitation", - description: "A request or offer to join or attend something.", - properties: [ - { - propertyType: expiredAtPropertyTypeId, - required: true, - }, - ], - }, - migrationState, - webShortname: "h", + const invitationEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Invitation", + description: "A request or offer to join or attend something.", + properties: [ + { + propertyType: expiredAtPropertyTypeId, + required: true, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); const invitationViaEmailEntityType = await createSystemEntityTypeIfNotExists( context, @@ -81,8 +73,10 @@ const migrate: MigrationFunction = async ({ }, ); - const invitationViaShortnameEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const invitationViaShortnameEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { title: "Invitation Via Shortname", description: "An invitation issued to a user via their shortname.", @@ -96,7 +90,8 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); const hasIssuedInvitationLinkType = await createSystemEntityTypeIfNotExists( context, @@ -121,14 +116,10 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const organizationEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentOrganizationEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const organizationEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentOrganizationEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!organizationEntityType) { throw new NotFoundError( @@ -156,12 +147,15 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId: updatedOrganizationEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: updatedOrganizationEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentOrganizationEntityTypeId, migrationState, newSchema: newOrganizationEntityTypeSchema, - }); + }, + ); /** * Step 3: Update the dependencies of the `Organization` entity type diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/022-add-migrations-completed-to-hash-instance.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/022-add-migrations-completed-to-hash-instance.migration.ts index 2416a9f160f..748b365ea80 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/022-add-migrations-completed-to-hash-instance.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/022-add-migrations-completed-to-hash-instance.migration.ts @@ -23,25 +23,23 @@ import type { MigrationFunction } from "../types"; * Together these allow subsequent startups to skip already-completed migrations * while still having access to the correct type version information. */ -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1: Create the property types for tracking migration state. */ - const migrationsCompletedPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const migrationsCompletedPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Migrations Completed", - description: - "The migrations that have been completed for this instance", + description: "The migrations that have been completed for this instance", possibleValues: [{ primitiveDataType: "text", array: true }], }, webShortname: "h", migrationState, - }); + }, + ); const migrationStatePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -66,19 +64,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const hashInstanceEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentHashInstanceEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const hashInstanceEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentHashInstanceEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!hashInstanceEntityType) { - throw new Error( - `Could not find entity type with ID ${currentHashInstanceEntityTypeId}`, - ); + throw new Error(`Could not find entity type with ID ${currentHashInstanceEntityTypeId}`); } const newHashInstanceEntityTypeSchema: EntityType = { @@ -94,15 +86,11 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId } = await updateSystemEntityType( - context, - authentication, - { - currentEntityTypeId: currentHashInstanceEntityTypeId, - migrationState, - newSchema: newHashInstanceEntityTypeSchema, - }, - ); + const { updatedEntityTypeId } = await updateSystemEntityType(context, authentication, { + currentEntityTypeId: currentHashInstanceEntityTypeId, + migrationState, + newSchema: newHashInstanceEntityTypeSchema, + }); /** * Step 3: Create temporary policies and upgrade HASH Instance entities. @@ -113,30 +101,27 @@ const migrate: MigrationFunction = async ({ webId: hashWebId, }).then((maybeMachineId) => { if (!maybeMachineId) { - throw new Error( - `Failed to get web bot account ID for web ID: ${hashWebId}`, - ); + throw new Error(`Failed to get web bot account ID for web ID: ${hashWebId}`); } return maybeMachineId; }); const instantiationPolicies = await Promise.all( - [updatedEntityTypeId, currentHashInstanceEntityTypeId].map( - async (entityTypeId) => - createPolicy(context.graphApi, authentication, { - name: `tmp-hash-instance-instantiate-hash-instance-v${extractVersion(entityTypeId)}`, - effect: "permit", - principal: { - type: "actor", - actorType: "machine", - id: hashWebBotAccountId, - }, - actions: ["instantiate"], - resource: { - type: "entityType", - id: entityTypeId, - }, - }), + [updatedEntityTypeId, currentHashInstanceEntityTypeId].map(async (entityTypeId) => + createPolicy(context.graphApi, authentication, { + name: `tmp-hash-instance-instantiate-hash-instance-v${extractVersion(entityTypeId)}`, + effect: "permit", + principal: { + type: "actor", + actorType: "machine", + id: hashWebBotAccountId, + }, + actions: ["instantiate"], + resource: { + type: "entityType", + id: entityTypeId, + }, + }), ), ); diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/023-create-more-custom-data-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/023-create-more-custom-data-types.migration.ts index d80819fab02..b706a8406a6 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/023-create-more-custom-data-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/023-create-more-custom-data-types.migration.ts @@ -4,11 +4,7 @@ import { createSystemDataTypeIfNotExists } from "../util"; import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], @@ -24,39 +20,31 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const durationDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - abstract: true, - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - title: "Duration", - description: "A measure of the length of time.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, + const durationDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + abstract: true, + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + title: "Duration", + description: "A measure of the length of time.", + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); - const secondDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: durationDataType.schema.$id }], - title: "Second", - description: - "The base unit of duration in the International System of Units (SI), defined as about 9 billion oscillations of the caesium atom.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, + const secondDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: durationDataType.schema.$id }], + title: "Second", + description: + "The base unit of duration in the International System of Units (SI), defined as about 9 billion oscillations of the caesium atom.", + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { @@ -98,8 +86,7 @@ const migrate: MigrationFunction = async ({ dataTypeDefinition: { allOf: [{ $ref: durationDataType.schema.$id }], title: "Minute", - description: - "A measure of the length of time, defined as exactly 60 seconds.", + description: "A measure of the length of time, defined as exactly 60 seconds.", type: "number", }, conversions: { @@ -116,8 +103,7 @@ const migrate: MigrationFunction = async ({ dataTypeDefinition: { allOf: [{ $ref: durationDataType.schema.$id }], title: "Hour", - description: - "A measure of the length of time, defined as exactly 3,600 seconds.", + description: "A measure of the length of time, defined as exactly 3,600 seconds.", type: "number", }, conversions: { diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/024-add-flow-types.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/024-add-flow-types.migration.ts index 53ad176ba9d..e2963aca5e0 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/024-add-flow-types.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/024-add-flow-types.migration.ts @@ -21,11 +21,7 @@ import { import type { MigrationFunction } from "../types"; import type { EntityType } from "@blockprotocol/type-system"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1: Create generic link types that will be used by Flow types. */ @@ -34,25 +30,21 @@ const migrate: MigrationFunction = async ({ * "Uses" link type - generic link for when something uses another thing. * Used by FlowRun and FlowSchedule to link to FlowDefinition. */ - const usesLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Uses", - titlePlural: "Uses", - icon: "🔗", - inverse: { - title: "Used By", - }, - description: "Something that uses something else.", - properties: [], - }, - webShortname: "h", - migrationState, + const usesLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Uses", + titlePlural: "Uses", + icon: "🔗", + inverse: { + title: "Used By", + }, + description: "Something that uses something else.", + properties: [], }, - ); + webShortname: "h", + migrationState, + }); /** * "Scheduled By" link type - links a FlowRun to the FlowSchedule that triggered it. @@ -81,8 +73,10 @@ const migrate: MigrationFunction = async ({ * Step 2: create the `Flow Definition` entity type. */ - const triggerDefinitionIdPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const triggerDefinitionIdPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Trigger Definition ID", description: "The ID of the trigger definition.", @@ -90,10 +84,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const outputDefinitionsPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const outputDefinitionsPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Output Definitions", description: "The output definitions of something.", @@ -106,10 +103,13 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); - const triggerDefinitionPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const triggerDefinitionPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Trigger Definition", description: "The trigger definition of a flow.", @@ -131,7 +131,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const stepDefinitionsPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -198,41 +199,32 @@ const migrate: MigrationFunction = async ({ /** * Flow Type data type - whether a flow is an AI flow or an integration flow. */ - const flowTypeDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "Flow Type", - description: - "The type of a flow, determining which task queue it runs on.", - enum: ["ai", "integration"], - type: "string", - }, - conversions: {}, - webShortname: "h", - migrationState, + const flowTypeDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "Flow Type", + description: "The type of a flow, determining which task queue it runs on.", + enum: ["ai", "integration"], + type: "string", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); - const scheduleStatusDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "Schedule Status", - description: - "The status of a schedule, indicating whether it is currently running or has been temporarily stopped.", - enum: ["active", "paused"], - type: "string", - }, - conversions: {}, - webShortname: "h", - migrationState, + const scheduleStatusDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "Schedule Status", + description: + "The status of a schedule, indicating whether it is currently running or has been temporarily stopped.", + enum: ["active", "paused"], + type: "string", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); const scheduleOverlapPolicyDataType = await createSystemDataTypeIfNotExists( context, @@ -252,20 +244,15 @@ const migrate: MigrationFunction = async ({ }, ); - const flowTypePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Flow Type", - description: - "The type of a flow, determining which task queue it runs on.", - possibleValues: [{ dataTypeId: flowTypeDataType.schema.$id }], - }, - webShortname: "h", - migrationState, + const flowTypePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Flow Type", + description: "The type of a flow, determining which task queue it runs on.", + possibleValues: [{ dataTypeId: flowTypeDataType.schema.$id }], }, - ); + webShortname: "h", + migrationState, + }); const scheduleSpecPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -281,27 +268,30 @@ const migrate: MigrationFunction = async ({ }, ); - const scheduleOverlapPolicyPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const scheduleOverlapPolicyPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Schedule Overlap Policy", description: "The policy for handling overlapping runs when a new scheduled execution is due but the previous one is still running.", - possibleValues: [ - { dataTypeId: scheduleOverlapPolicyDataType.schema.$id }, - ], + possibleValues: [{ dataTypeId: scheduleOverlapPolicyDataType.schema.$id }], }, webShortname: "h", migrationState, - }); + }, + ); const millisecondDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "millisecond", migrationState, }); - const scheduleCatchupWindowPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const scheduleCatchupWindowPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Schedule Catchup Window", description: "How far back to catch up missed runs after downtime.", @@ -309,7 +299,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const pauseOnFailurePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -331,8 +322,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Schedule Status", - description: - "The current status of a schedule - either active or paused.", + description: "The current status of a schedule - either active or paused.", possibleValues: [{ dataTypeId: scheduleStatusDataType.schema.$id }], }, webShortname: "h", @@ -345,8 +335,10 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const schedulePausedAtPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const schedulePausedAtPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Paused At", description: "The timestamp at which something was paused.", @@ -354,7 +346,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const explanationPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -370,8 +363,10 @@ const migrate: MigrationFunction = async ({ }, ); - const schedulePauseStatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const schedulePauseStatePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Schedule Pause State", description: @@ -394,7 +389,8 @@ const migrate: MigrationFunction = async ({ }, webShortname: "h", migrationState, - }); + }, + ); const dataSourcesPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -428,160 +424,146 @@ const migrate: MigrationFunction = async ({ }, ); - const outputsPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Outputs", - description: "The outputs of something.", - possibleValues: [ - /** @todo: consider constraining this type further */ - { - primitiveDataType: "object", - array: true, - }, - ], - }, - webShortname: "h", - migrationState, + const outputsPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Outputs", + description: "The outputs of something.", + possibleValues: [ + /** @todo: consider constraining this type further */ + { + primitiveDataType: "object", + array: true, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); - const triggerPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Trigger", - description: "The trigger of a flow.", - possibleValues: [ - { - propertyTypeObjectProperties: { - [triggerDefinitionIdPropertyType.metadata.recordId.baseUrl]: { - $ref: triggerDefinitionIdPropertyType.schema.$id, - }, - [outputsPropertyType.metadata.recordId.baseUrl]: { - $ref: outputsPropertyType.schema.$id, - }, + const triggerPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Trigger", + description: "The trigger of a flow.", + possibleValues: [ + { + propertyTypeObjectProperties: { + [triggerDefinitionIdPropertyType.metadata.recordId.baseUrl]: { + $ref: triggerDefinitionIdPropertyType.schema.$id, + }, + [outputsPropertyType.metadata.recordId.baseUrl]: { + $ref: outputsPropertyType.schema.$id, }, - propertyTypeObjectRequiredProperties: [ - triggerDefinitionIdPropertyType.metadata.recordId.baseUrl, - ], }, - ], - }, - webShortname: "h", - migrationState, + propertyTypeObjectRequiredProperties: [ + triggerDefinitionIdPropertyType.metadata.recordId.baseUrl, + ], + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** * Flow Definition ID property type - stores the ID of the flow definition. * This is used until we start persisting Flow Definitions to the graph, * at which point we'll use the "Uses" link type instead. */ - const flowDefinitionIdPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Flow Definition ID", - description: "The ID of a flow definition.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, - }); - - const stepsPropertyType = await createSystemPropertyTypeIfNotExists( + const flowDefinitionIdPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "Step", - description: "A step in a flow run.", - possibleValues: [ - /** @todo: consider constraining this type further. */ - { - primitiveDataType: "object", - array: true, - }, - ], + title: "Flow Definition ID", + description: "The ID of a flow definition.", + possibleValues: [{ primitiveDataType: "text" }], }, webShortname: "h", migrationState, }, ); - const flowScheduleEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Flow Schedule", - titlePlural: "Flow Schedules", - icon: "🗓️", - description: - "A schedule that triggers recurring executions of a flow definition.", - labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: flowDefinitionIdPropertyType, - required: true, - }, - { - propertyType: flowTypePropertyType, - required: true, - }, - { - propertyType: scheduleSpecPropertyType, - required: true, - }, - { - propertyType: scheduleOverlapPolicyPropertyType, - required: true, - }, - { - propertyType: scheduleCatchupWindowPropertyType, - }, - { - propertyType: pauseOnFailurePropertyType, - }, - { - propertyType: scheduleStatusPropertyType, - required: true, - }, - { - propertyType: schedulePauseStatePropertyType, - }, - { - propertyType: dataSourcesPropertyType, - }, - { - propertyType: triggerPropertyType, - required: true, - }, - ], - /** - * Note: The "Uses" link to FlowDefinition is defined here for future use, - * but is not currently created since Flow Definitions aren't persisted to the graph yet. - */ - outgoingLinks: [ - { - linkEntityType: usesLinkEntityType, - destinationEntityTypes: [flowDefinitionEntityType], - minItems: 0, - maxItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, + const stepsPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Step", + description: "A step in a flow run.", + possibleValues: [ + /** @todo: consider constraining this type further. */ + { + primitiveDataType: "object", + array: true, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); + + const flowScheduleEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Flow Schedule", + titlePlural: "Flow Schedules", + icon: "🗓️", + description: "A schedule that triggers recurring executions of a flow definition.", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: flowDefinitionIdPropertyType, + required: true, + }, + { + propertyType: flowTypePropertyType, + required: true, + }, + { + propertyType: scheduleSpecPropertyType, + required: true, + }, + { + propertyType: scheduleOverlapPolicyPropertyType, + required: true, + }, + { + propertyType: scheduleCatchupWindowPropertyType, + }, + { + propertyType: pauseOnFailurePropertyType, + }, + { + propertyType: scheduleStatusPropertyType, + required: true, + }, + { + propertyType: schedulePauseStatePropertyType, + }, + { + propertyType: dataSourcesPropertyType, + }, + { + propertyType: triggerPropertyType, + required: true, + }, + ], + /** + * Note: The "Uses" link to FlowDefinition is defined here for future use, + * but is not currently created since Flow Definitions aren't persisted to the graph yet. + */ + outgoingLinks: [ + { + linkEntityType: usesLinkEntityType, + destinationEntityTypes: [flowDefinitionEntityType], + minItems: 0, + maxItems: 1, + }, + ], + }, + webShortname: "h", + migrationState, + }); /** * FlowRun entity type - has flowDefinitionId property and optionally @@ -589,59 +571,55 @@ const migrate: MigrationFunction = async ({ * Note: The "Uses" link to FlowDefinition is defined for future use, * but flowDefinitionId property is used until Flow Definitions are persisted. */ - const flowEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Flow Run", - titlePlural: "Flow Runs", - icon: "▶️", - description: "An execution run of a flow.", - labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: workflowIdPropertyType, - required: true, - }, - { - propertyType: flowDefinitionIdPropertyType, - required: true, - }, - { - propertyType: triggerPropertyType, - required: true, - }, - { - propertyType: stepsPropertyType, - required: true, - }, - { - propertyType: outputsPropertyType, - }, - ], - outgoingLinks: [ - { - linkEntityType: usesLinkEntityType, - destinationEntityTypes: [flowDefinitionEntityType], - minItems: 0, - maxItems: 1, - }, - { - linkEntityType: scheduledByLinkEntityType, - destinationEntityTypes: [flowScheduleEntityType], - maxItems: 1, - }, - ], - }, - webShortname: "h", - migrationState, + const flowEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Flow Run", + titlePlural: "Flow Runs", + icon: "▶️", + description: "An execution run of a flow.", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: workflowIdPropertyType, + required: true, + }, + { + propertyType: flowDefinitionIdPropertyType, + required: true, + }, + { + propertyType: triggerPropertyType, + required: true, + }, + { + propertyType: stepsPropertyType, + required: true, + }, + { + propertyType: outputsPropertyType, + }, + ], + outgoingLinks: [ + { + linkEntityType: usesLinkEntityType, + destinationEntityTypes: [flowDefinitionEntityType], + minItems: 0, + maxItems: 1, + }, + { + linkEntityType: scheduledByLinkEntityType, + destinationEntityTypes: [flowScheduleEntityType], + maxItems: 1, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** * Step 3: Create a 'Claim' entity type. @@ -649,108 +627,87 @@ const migrate: MigrationFunction = async ({ * Each claim has a subject, and may have an object. * The subject and object may be only plain text, or potentially also a linked entity if and when one is available. */ - const objectPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Object", - description: "What something is directed towards.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const objectPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Object", + description: "What something is directed towards.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); - const subjectPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Subject", - description: "A thing or theme that something is about.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webShortname: "h", - migrationState, + const subjectPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Subject", + description: "A thing or theme that something is about.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webShortname: "h", + migrationState, + }); - const hasSubjectEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Subject", - /** @todo icon */ - inverse: { - title: "Subject Of", - }, - description: "The subject something has", - properties: [], + const hasSubjectEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Subject", + /** @todo icon */ + inverse: { + title: "Subject Of", }, - webShortname: "h", - migrationState, + description: "The subject something has", + properties: [], }, - ); + webShortname: "h", + migrationState, + }); - const hasObjectEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Object", - /** @todo icon */ - inverse: { - title: "Object Of", - }, - description: "The object something has", - properties: [], + const hasObjectEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Object", + /** @todo icon */ + inverse: { + title: "Object Of", }, - webShortname: "h", - migrationState, + description: "The object something has", + properties: [], }, - ); + webShortname: "h", + migrationState, + }); - const _claimEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Claim", - titlePlural: "Claims", - icon: "💬", - description: "A claim made about something.", - properties: [ - { - propertyType: - blockProtocolPropertyTypes.textualContent.propertyTypeId, - required: true, - }, - { - propertyType: subjectPropertyType, - required: true, - }, - { - propertyType: objectPropertyType, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasSubjectEntityType, - }, - { - linkEntityType: hasObjectEntityType, - }, - ], - }, - webShortname: "h", - migrationState, + const _claimEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Claim", + titlePlural: "Claims", + icon: "💬", + description: "A claim made about something.", + properties: [ + { + propertyType: blockProtocolPropertyTypes.textualContent.propertyTypeId, + required: true, + }, + { + propertyType: subjectPropertyType, + required: true, + }, + { + propertyType: objectPropertyType, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasSubjectEntityType, + }, + { + linkEntityType: hasObjectEntityType, + }, + ], }, - ); + webShortname: "h", + migrationState, + }); /** * Step 4: create a `Incurred In` link entity type @@ -786,19 +743,13 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const usageRecordEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentUsageRecordEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const usageRecordEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentUsageRecordEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!usageRecordEntityType) { - throw new NotFoundError( - `Could not find entity type with ID ${currentUsageRecordEntityTypeId}`, - ); + throw new NotFoundError(`Could not find entity type with ID ${currentUsageRecordEntityTypeId}`); } const customMetadataPropertyType = await createSystemPropertyTypeIfNotExists( @@ -834,12 +785,15 @@ const migrate: MigrationFunction = async ({ }, }; - const { updatedEntityTypeId: _updatedUsageRecordEntityTypeId } = - await updateSystemEntityType(context, authentication, { + const { updatedEntityTypeId: _updatedUsageRecordEntityTypeId } = await updateSystemEntityType( + context, + authentication, + { currentEntityTypeId: currentUsageRecordEntityTypeId, migrationState, newSchema: newUsageRecordEntityTypeSchema, - }); + }, + ); /** * Step 4: Upgrade existing usage record entities to the latest version diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/086-add-study-record-type.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/086-add-study-record-type.dev.migration.ts index 954d4963d55..92cfc7b5846 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/086-add-study-record-type.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/086-add-study-record-type.dev.migration.ts @@ -16,61 +16,45 @@ import { import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** Data types */ - const phaseDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "Trial Phase", - description: - "The distinct stage of a clinical trial, categorizing the study's primary goals and level of testing. Phase 0 involves very limited human testing, Phase 1 tests safety, dosage, and administration, Phase 2 tests effectiveness, Phase 3 confirms benefits, and Phase 4 studies long-term effects.", - type: "string", - }, - conversions: {}, - migrationState, - webShortname: "h", + const phaseDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "Trial Phase", + description: + "The distinct stage of a clinical trial, categorizing the study's primary goals and level of testing. Phase 0 involves very limited human testing, Phase 1 tests safety, dosage, and administration, Phase 2 tests effectiveness, Phase 3 confirms benefits, and Phase 4 studies long-term effects.", + type: "string", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const nctIdDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "NCT ID", - description: - "National Clinical Trial (NCT) Identifier Number, which is a unique identifier assigned to each clinical trial registered with ClinicalTrials.gov.", - type: "string", - }, - conversions: {}, - migrationState, - webShortname: "h", + const nctIdDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "NCT ID", + description: + "National Clinical Trial (NCT) Identifier Number, which is a unique identifier assigned to each clinical trial registered with ClinicalTrials.gov.", + type: "string", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); /** Property types */ - const objectivePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Objective", - description: "The goal or aim of something.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const objectivePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Objective", + description: "The goal or aim of something.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); const trialPhasePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -78,8 +62,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Trial Phase", - description: - "The stage of a clinical trial studying a drug or biological product.", + description: "The stage of a clinical trial studying a drug or biological product.", possibleValues: [{ dataTypeId: phaseDataType.schema.$id }], }, migrationState, @@ -92,8 +75,10 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const actualEnrollmentPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const actualEnrollmentPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Actual Enrollment", description: "The actual number of participants enrolled in something.", @@ -101,15 +86,18 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); const dateDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "date", migrationState, }); - const actualStudyStartDatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const actualStudyStartDatePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Actual Study Start Date", description: @@ -118,10 +106,13 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); - const actualPrimaryCompletionDatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const actualPrimaryCompletionDatePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Actual Study Primary Completion Date", description: @@ -130,10 +121,13 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); - const actualStudyCompletionDatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const actualStudyCompletionDatePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Actual Study Completion Date", description: @@ -142,22 +136,27 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); - const estimatedEnrollmentPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const estimatedEnrollmentPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Estimated Enrollment", - description: - "The estimated number of participants that will be enrolled in something.", + description: "The estimated number of participants that will be enrolled in something.", possibleValues: [{ dataTypeId: integerDataTypeId }], }, migrationState, webShortname: "h", - }); + }, + ); - const estimatedStudyStartDatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const estimatedStudyStartDatePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Estimated Study Start Date", description: @@ -166,10 +165,13 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); - const estimatedPrimaryCompletionDatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const estimatedPrimaryCompletionDatePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Estimated Primary Completion Date", description: @@ -178,101 +180,76 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); - - const estimatedStudyCompletionDatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Estimated Study Completion Date", - description: - "The estimated date on which the last participant in a clinical study will be examined or receive an intervention to collect final data for the primary outcome measures, secondary outcome measures, and adverse events (that is, the last participant's last visit).", - possibleValues: [{ dataTypeId: dateDataTypeId }], - }, - migrationState, - webShortname: "h", - }); + }, + ); - const nctIdPropertyType = await createSystemPropertyTypeIfNotExists( + const estimatedStudyCompletionDatePropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "NCT ID", + title: "Estimated Study Completion Date", description: - "The National Clinical Trial (NCT) Identifier Number for a study registered with ClinicalTrials.gov", - possibleValues: [{ dataTypeId: nctIdDataType.schema.$id }], + "The estimated date on which the last participant in a clinical study will be examined or receive an intervention to collect final data for the primary outcome measures, secondary outcome measures, and adverse events (that is, the last participant's last visit).", + possibleValues: [{ dataTypeId: dateDataTypeId }], }, migrationState, webShortname: "h", }, ); - const isrctnIdDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "ISRCTN", - description: - "The unique id for a study registered with the ISRCTN Registry.", - type: "string", - }, - conversions: {}, - migrationState, - webShortname: "h", + const nctIdPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "NCT ID", + description: + "The National Clinical Trial (NCT) Identifier Number for a study registered with ClinicalTrials.gov", + possibleValues: [{ dataTypeId: nctIdDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); - const isrctnIdPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "ISRCTN", - description: "The ISRCTN Registry identifier for something.", - possibleValues: [{ dataTypeId: isrctnIdDataType.schema.$id }], - }, - migrationState, - webShortname: "h", + const isrctnIdDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "ISRCTN", + description: "The unique id for a study registered with the ISRCTN Registry.", + type: "string", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const studyTypePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Study Type", - description: - "Describes the nature of a clinical study. Study types include interventional studies, which aim to find out more about a particular intervention by assigning people to different treatment groups, and observational studies, where the researchers do not influence what treatment the participants receive.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const isrctnIdPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "ISRCTN", + description: "The ISRCTN Registry identifier for something.", + possibleValues: [{ dataTypeId: isrctnIdDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); - const medicalConditionPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Medical Condition", - description: - "A disease, disorder, syndrome, illness, or injury, which may relate to either or both of physical and mental health.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", - }); + const studyTypePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Study Type", + description: + "Describes the nature of a clinical study. Study types include interventional studies, which aim to find out more about a particular intervention by assigning people to different treatment groups, and observational studies, where the researchers do not influence what treatment the participants receive.", + possibleValues: [{ primitiveDataType: "text" }], + }, + migrationState, + webShortname: "h", + }); - const timeFramePropertyType = await createSystemPropertyTypeIfNotExists( + const medicalConditionPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "Time Frame", + title: "Medical Condition", description: - "The time period over which something occurs or is measured.", + "A disease, disorder, syndrome, illness, or injury, which may relate to either or both of physical and mental health.", possibleValues: [{ primitiveDataType: "text" }], }, migrationState, @@ -280,6 +257,16 @@ const migrate: MigrationFunction = async ({ }, ); + const timeFramePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Time Frame", + description: "The time period over which something occurs or is measured.", + possibleValues: [{ primitiveDataType: "text" }], + }, + migrationState, + webShortname: "h", + }); + const outcomeMeasurePropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, @@ -326,43 +313,41 @@ const migrate: MigrationFunction = async ({ }, ); - const studyArmPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Study Arm", - description: - "A specific treatment group in a clinical trial. Each arm represents a unique intervention strategy or control group, allowing researchers to compare outcomes between different approaches.", - possibleValues: [ - { - propertyTypeObjectProperties: { - [blockProtocolPropertyTypes.name.propertyTypeBaseUrl]: { - $ref: blockProtocolPropertyTypes.name.propertyTypeId, - }, - [interventionPropertyType.metadata.recordId.baseUrl]: { - $ref: interventionPropertyType.schema.$id, - }, - [systemPropertyTypes.methodology.propertyTypeBaseUrl]: { - $ref: getCurrentHashPropertyTypeId({ - propertyTypeKey: "methodology", - migrationState, - }), - }, + const studyArmPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Study Arm", + description: + "A specific treatment group in a clinical trial. Each arm represents a unique intervention strategy or control group, allowing researchers to compare outcomes between different approaches.", + possibleValues: [ + { + propertyTypeObjectProperties: { + [blockProtocolPropertyTypes.name.propertyTypeBaseUrl]: { + $ref: blockProtocolPropertyTypes.name.propertyTypeId, + }, + [interventionPropertyType.metadata.recordId.baseUrl]: { + $ref: interventionPropertyType.schema.$id, + }, + [systemPropertyTypes.methodology.propertyTypeBaseUrl]: { + $ref: getCurrentHashPropertyTypeId({ + propertyTypeKey: "methodology", + migrationState, + }), }, - propertyTypeObjectRequiredProperties: [ - blockProtocolPropertyTypes.name.propertyTypeBaseUrl, - ], }, - ], - }, - migrationState, - webShortname: "h", + propertyTypeObjectRequiredProperties: [ + blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + ], + }, + ], }, - ); + migrationState, + webShortname: "h", + }); - const inclusionCriteriaPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const inclusionCriteriaPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Inclusion Criteria", description: @@ -371,27 +356,17 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); - - const exclusionCriteriaPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { - propertyTypeDefinition: { - title: "Exclusion Criteria", - description: - "Criteria that would prevent someone or something from being included in something.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", - }); + }, + ); - const statusPropertyType = await createSystemPropertyTypeIfNotExists( + const exclusionCriteriaPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { - title: "Status", - description: "The status of something.", + title: "Exclusion Criteria", + description: + "Criteria that would prevent someone or something from being included in something.", possibleValues: [{ primitiveDataType: "text" }], }, migrationState, @@ -399,19 +374,25 @@ const migrate: MigrationFunction = async ({ }, ); - const contactLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Contact", - description: "A contact for something (an organization, project, etc.)", - }, - migrationState, - webShortname: "h", + const statusPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Status", + description: "The status of something.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); + + const contactLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Contact", + description: "A contact for something (an organization, project, etc.)", + }, + migrationState, + webShortname: "h", + }); const sponsoredByLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -465,8 +446,10 @@ const migrate: MigrationFunction = async ({ migrationState, }); - const _clinicalTrialRecordEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const _clinicalTrialRecordEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { allOf: [docEntityTypeId], title: "Study Record", @@ -567,10 +550,7 @@ const migrate: MigrationFunction = async ({ ], outgoingLinks: [ { - destinationEntityTypes: [ - personEntityTypeId, - institutionEntityTypeId, - ], + destinationEntityTypes: [personEntityTypeId, institutionEntityTypeId], linkEntityType: sponsoredByLinkEntityType.schema.$id, }, { @@ -585,7 +565,8 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); return migrationState; }; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts index 435a913b2a2..57931e19f28 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/087-add-initial-currency-data-types.dev.migration.ts @@ -4,28 +4,20 @@ import { createSystemDataTypeIfNotExists } from "../util"; import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { - const currencyDataTypes = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - abstract: true, - title: "Currency", - description: - "A system of money in common use within a specific environment over time, especially for people in a nation state.", - type: "number", - }, - conversions: {}, - webShortname: "h", - migrationState, +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { + const currencyDataTypes = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Currency", + description: + "A system of money in common use within a specific environment over time, especially for people in a nation state.", + type: "number", }, - ); + conversions: {}, + webShortname: "h", + migrationState, + }); await createSystemDataTypeIfNotExists(context, authentication, { dataTypeDefinition: { diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/090-add-aviation-types.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/090-add-aviation-types.dev.migration.ts index c7f729ae636..cb77a003403 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/090-add-aviation-types.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/090-add-aviation-types.dev.migration.ts @@ -13,11 +13,7 @@ import { import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { /** * Step 1: Create data types */ @@ -26,123 +22,95 @@ const migrate: MigrationFunction = async ({ * Angle data type hierarchy: Angle → Degree → Latitude/Longitude */ - const angleDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - abstract: true, - title: "Angle", - description: - "A measure of rotation or the space between two intersecting lines.", - type: "number", - }, - conversions: {}, - migrationState, - webShortname: "h", + const angleDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Angle", + description: "A measure of rotation or the space between two intersecting lines.", + type: "number", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const degreeDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: angleDataType.schema.$id }], - title: "Degree", - description: - "A unit of angular measure equal to 1/360 of a full rotation.", - label: { - right: "°", - }, - type: "number", + const degreeDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: angleDataType.schema.$id }], + title: "Degree", + description: "A unit of angular measure equal to 1/360 of a full rotation.", + label: { + right: "°", }, - conversions: {}, - migrationState, - webShortname: "h", + type: "number", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const latitudeDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: degreeDataType.schema.$id }], - title: "Latitude", - description: - "The angular distance of a position north or south of the equator, ranging from -90° (South Pole) to +90° (North Pole).", - minimum: -90, - maximum: 90, - type: "number", - }, - conversions: {}, - migrationState, - webShortname: "h", - }, - ); + const latitudeDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: degreeDataType.schema.$id }], + title: "Latitude", + description: + "The angular distance of a position north or south of the equator, ranging from -90° (South Pole) to +90° (North Pole).", + minimum: -90, + maximum: 90, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }); - const longitudeDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: degreeDataType.schema.$id }], - title: "Longitude", - description: - "The angular distance of a position east or west of the prime meridian, ranging from -180° to +180°.", - minimum: -180, - maximum: 180, - type: "number", - }, - conversions: {}, - migrationState, - webShortname: "h", - }, - ); + const longitudeDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: degreeDataType.schema.$id }], + title: "Longitude", + description: + "The angular distance of a position east or west of the prime meridian, ranging from -180° to +180°.", + minimum: -180, + maximum: 180, + type: "number", + }, + conversions: {}, + migrationState, + webShortname: "h", + }); /** * Speed data type hierarchy: Speed → Meters per Second (canonical) → km/h, knots, ft/min */ - const speedDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], - abstract: true, - title: "Speed", - description: - "A measure of the rate of movement or change in position over time.", - type: "number", - }, - conversions: {}, - migrationState, - webShortname: "h", + const speedDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.number.dataTypeId }], + abstract: true, + title: "Speed", + description: "A measure of the rate of movement or change in position over time.", + type: "number", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); - const metersPerSecondDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: speedDataType.schema.$id }], - title: "Meters per Second", - description: - "The SI unit of speed, expressing the number of meters traveled in one second.", - label: { - right: "m/s", - }, - type: "number", + const metersPerSecondDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: speedDataType.schema.$id }], + title: "Meters per Second", + description: "The SI unit of speed, expressing the number of meters traveled in one second.", + label: { + right: "m/s", }, - conversions: {}, - migrationState, - webShortname: "h", + type: "number", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); const _kilometersPerHourDataType = await createSystemDataTypeIfNotExists( context, @@ -151,8 +119,7 @@ const migrate: MigrationFunction = async ({ dataTypeDefinition: { allOf: [{ $ref: speedDataType.schema.$id }], title: "Kilometers per Hour", - description: - "A unit of speed expressing the number of kilometers traveled in one hour.", + description: "A unit of speed expressing the number of kilometers traveled in one hour.", label: { right: "km/h", }, @@ -184,149 +151,125 @@ const migrate: MigrationFunction = async ({ }, ); - const knotsDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: speedDataType.schema.$id }], - title: "Knots", - description: - "A unit of speed equal to one nautical mile per hour, commonly used in aviation and maritime contexts.", - label: { - right: "kn", - }, - type: "number", + const knotsDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: speedDataType.schema.$id }], + title: "Knots", + description: + "A unit of speed equal to one nautical mile per hour, commonly used in aviation and maritime contexts.", + label: { + right: "kn", }, - conversions: { - [metersPerSecondDataType.metadata.recordId.baseUrl]: { - // 1 knot = 1852m / 3600s (1 nautical mile = 1852m exactly) - // m/s → knots: self * 3600 / 1852 - from: { - expression: [ - "/", - ["*", "self", { const: 3600, type: "number" }], - { const: 1852, type: "number" }, - ], - }, - // knots → m/s: self * 1852 / 3600 - to: { - expression: [ - "/", - ["*", "self", { const: 1852, type: "number" }], - { const: 3600, type: "number" }, - ], - }, + type: "number", + }, + conversions: { + [metersPerSecondDataType.metadata.recordId.baseUrl]: { + // 1 knot = 1852m / 3600s (1 nautical mile = 1852m exactly) + // m/s → knots: self * 3600 / 1852 + from: { + expression: [ + "/", + ["*", "self", { const: 3600, type: "number" }], + { const: 1852, type: "number" }, + ], + }, + // knots → m/s: self * 1852 / 3600 + to: { + expression: [ + "/", + ["*", "self", { const: 1852, type: "number" }], + { const: 3600, type: "number" }, + ], }, }, - migrationState, - webShortname: "h", }, - ); + migrationState, + webShortname: "h", + }); - const feetPerMinuteDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: speedDataType.schema.$id }], - title: "Feet per Minute", - description: - "A unit of vertical speed commonly used in aviation to measure rate of climb or descent.", - label: { - right: "ft/min", + const feetPerMinuteDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: speedDataType.schema.$id }], + title: "Feet per Minute", + description: + "A unit of vertical speed commonly used in aviation to measure rate of climb or descent.", + label: { + right: "ft/min", + }, + type: "number", + }, + conversions: { + [metersPerSecondDataType.metadata.recordId.baseUrl]: { + // 1 ft/min = 0.3048m / 60s (1 foot = 0.3048m exactly) + // m/s → ft/min: self * 60 / 0.3048 + from: { + expression: [ + "/", + ["*", "self", { const: 60, type: "number" }], + { const: 0.3048, type: "number" }, + ], }, - type: "number", - }, - conversions: { - [metersPerSecondDataType.metadata.recordId.baseUrl]: { - // 1 ft/min = 0.3048m / 60s (1 foot = 0.3048m exactly) - // m/s → ft/min: self * 60 / 0.3048 - from: { - expression: [ - "/", - ["*", "self", { const: 60, type: "number" }], - { const: 0.3048, type: "number" }, - ], - }, - // ft/min → m/s: self * 0.3048 / 60 - to: { - expression: [ - "/", - ["*", "self", { const: 0.3048, type: "number" }], - { const: 60, type: "number" }, - ], - }, + // ft/min → m/s: self * 0.3048 / 60 + to: { + expression: [ + "/", + ["*", "self", { const: 0.3048, type: "number" }], + { const: 60, type: "number" }, + ], }, }, - migrationState, - webShortname: "h", }, - ); + migrationState, + webShortname: "h", + }); /** * Step 2: Create property types */ - const iataCodePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "IATA Code", - description: - "A code assigned by the International Air Transport Association (IATA) to identify airports, airlines, or aircraft types.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const iataCodePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "IATA Code", + description: + "A code assigned by the International Air Transport Association (IATA) to identify airports, airlines, or aircraft types.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); - const icaoCodePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "ICAO Code", - description: - "A code assigned by the International Civil Aviation Organization (ICAO) to identify airports, airlines, or aircraft types.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const icaoCodePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "ICAO Code", + description: + "A code assigned by the International Civil Aviation Organization (ICAO) to identify airports, airlines, or aircraft types.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); - const gatePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Gate", - description: - "The gate number or identifier at an airport terminal where passengers board or disembark.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const gatePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Gate", + description: + "The gate number or identifier at an airport terminal where passengers board or disembark.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); - const terminalPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Terminal", - description: - "The terminal building or area at an airport where passengers check in, wait, and board flights.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const terminalPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Terminal", + description: + "The terminal building or area at an airport where passengers check in, wait, and board flights.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); const baggageClaimPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -376,8 +319,10 @@ const migrate: MigrationFunction = async ({ /** * Gate times (pushback/arrival at gate) */ - const scheduledGateTimePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const scheduledGateTimePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Scheduled Gate Time", description: @@ -386,19 +331,22 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); - const estimatedGateTimePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const estimatedGateTimePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Estimated Gate Time", - description: - "The predicted date and time for gate departure (pushback) or arrival.", + description: "The predicted date and time for gate departure (pushback) or arrival.", possibleValues: [{ dataTypeId: datetimeDataTypeId }], }, migrationState, webShortname: "h", - }); + }, + ); const actualGateTimePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -406,8 +354,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Actual Gate Time", - description: - "The actual date and time of gate departure (pushback) or arrival.", + description: "The actual date and time of gate departure (pushback) or arrival.", possibleValues: [{ dataTypeId: datetimeDataTypeId }], }, migrationState, @@ -418,8 +365,10 @@ const migrate: MigrationFunction = async ({ /** * Runway times (takeoff/touchdown) */ - const scheduledRunwayTimePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const scheduledRunwayTimePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Scheduled Runway Time", description: @@ -428,10 +377,13 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); - const estimatedRunwayTimePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const estimatedRunwayTimePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Estimated Runway Time", description: @@ -440,10 +392,13 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); - const actualRunwayTimePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const actualRunwayTimePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Actual Runway Time", description: @@ -452,7 +407,8 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); const flightNumberPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -469,30 +425,19 @@ const migrate: MigrationFunction = async ({ }, ); - const flightStatusDataType = await createSystemDataTypeIfNotExists( - context, - authentication, - { - dataTypeDefinition: { - allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], - title: "Flight Status", - description: - "The current operational status of a flight, indicating whether it is scheduled, in progress, completed, or has encountered issues.", - enum: [ - "Scheduled", - "Active", - "Landed", - "Cancelled", - "Incident", - "Diverted", - ], - type: "string", - }, - conversions: {}, - migrationState, - webShortname: "h", + const flightStatusDataType = await createSystemDataTypeIfNotExists(context, authentication, { + dataTypeDefinition: { + allOf: [{ $ref: blockProtocolDataTypes.text.dataTypeId }], + title: "Flight Status", + description: + "The current operational status of a flight, indicating whether it is scheduled, in progress, completed, or has encountered issues.", + enum: ["Scheduled", "Active", "Landed", "Cancelled", "Incident", "Diverted"], + type: "string", }, - ); + conversions: {}, + migrationState, + webShortname: "h", + }); const flightStatusPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -514,8 +459,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Flight Date", - description: - "The calendar date on which a flight is scheduled to operate.", + description: "The calendar date on which a flight is scheduled to operate.", possibleValues: [{ dataTypeId: dateDataTypeId }], }, migrationState, @@ -523,48 +467,35 @@ const migrate: MigrationFunction = async ({ }, ); - const timezonePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Timezone", - description: - "A time zone identifier (e.g. 'America/Los_Angeles', 'Europe/London').", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const timezonePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Timezone", + description: "A time zone identifier (e.g. 'America/Los_Angeles', 'Europe/London').", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); - const cityPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "City", - description: "The city where something is located, occurred, etc.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const cityPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "City", + description: "The city where something is located, occurred, etc.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); - const runwayPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Runway", - description: "The runway identifier used for takeoff or landing.", - possibleValues: [{ primitiveDataType: "text" }], - }, - migrationState, - webShortname: "h", + const runwayPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Runway", + description: "The runway identifier used for takeoff or landing.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + migrationState, + webShortname: "h", + }); const flightTypePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -580,35 +511,33 @@ const migrate: MigrationFunction = async ({ }, ); - const codesharePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Codeshare", - description: - "A codeshare flight number, where multiple airlines sell seats on the same flight under their own flight numbers.", - possibleValues: [ - { - propertyTypeObjectProperties: { - [iataCodePropertyType.metadata.recordId.baseUrl]: { - $ref: iataCodePropertyType.schema.$id, - }, - [icaoCodePropertyType.metadata.recordId.baseUrl]: { - $ref: icaoCodePropertyType.schema.$id, - }, + const codesharePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Codeshare", + description: + "A codeshare flight number, where multiple airlines sell seats on the same flight under their own flight numbers.", + possibleValues: [ + { + propertyTypeObjectProperties: { + [iataCodePropertyType.metadata.recordId.baseUrl]: { + $ref: iataCodePropertyType.schema.$id, + }, + [icaoCodePropertyType.metadata.recordId.baseUrl]: { + $ref: icaoCodePropertyType.schema.$id, }, - propertyTypeObjectRequiredProperties: [], }, - ], - }, - migrationState, - webShortname: "h", + propertyTypeObjectRequiredProperties: [], + }, + ], }, - ); + migrationState, + webShortname: "h", + }); - const registrationNumberPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const registrationNumberPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Registration Number", description: @@ -617,72 +546,54 @@ const migrate: MigrationFunction = async ({ }, migrationState, webShortname: "h", - }); + }, + ); const metersDataTypeId = getCurrentHashDataTypeId({ dataTypeKey: "meters", migrationState, }); - const latitudePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Latitude", - description: - "The angular distance of a position north or south of the equator.", - possibleValues: [{ dataTypeId: latitudeDataType.schema.$id }], - }, - migrationState, - webShortname: "h", + const latitudePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Latitude", + description: "The angular distance of a position north or south of the equator.", + possibleValues: [{ dataTypeId: latitudeDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); - const longitudePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Longitude", - description: - "The angular distance of a position east or west of the prime meridian.", - possibleValues: [{ dataTypeId: longitudeDataType.schema.$id }], - }, - migrationState, - webShortname: "h", + const longitudePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Longitude", + description: "The angular distance of a position east or west of the prime meridian.", + possibleValues: [{ dataTypeId: longitudeDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); - const altitudePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Altitude", - description: - "The height of an object above a reference point, such as sea level or the ground.", - possibleValues: [{ dataTypeId: metersDataTypeId }], - }, - migrationState, - webShortname: "h", + const altitudePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Altitude", + description: + "The height of an object above a reference point, such as sea level or the ground.", + possibleValues: [{ dataTypeId: metersDataTypeId }], }, - ); + migrationState, + webShortname: "h", + }); - const directionPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Direction", - description: - "The heading or bearing of something, measured in degrees from true north.", - possibleValues: [{ dataTypeId: degreeDataType.schema.$id }], - }, - migrationState, - webShortname: "h", + const directionPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Direction", + description: "The heading or bearing of something, measured in degrees from true north.", + possibleValues: [{ dataTypeId: degreeDataType.schema.$id }], }, - ); + migrationState, + webShortname: "h", + }); const groundSpeedPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -690,8 +601,7 @@ const migrate: MigrationFunction = async ({ { propertyTypeDefinition: { title: "Ground Speed", - description: - "The horizontal speed of an aircraft relative to the ground.", + description: "The horizontal speed of an aircraft relative to the ground.", possibleValues: [{ dataTypeId: knotsDataType.schema.$id }], }, migrationState, @@ -731,95 +641,81 @@ const migrate: MigrationFunction = async ({ * Step 2: Create entity types */ - const airportEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Airport", - titlePlural: "Airports", - icon: "🏢", - description: - "A facility where aircraft take off and land, with infrastructure for passenger and cargo services.", - labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: iataCodePropertyType, - }, - { - propertyType: icaoCodePropertyType, - }, - { - propertyType: timezonePropertyType, - }, - { - propertyType: cityPropertyType, - }, - ], - }, - migrationState, - webShortname: "h", + const airportEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Airport", + titlePlural: "Airports", + icon: "🏢", + description: + "A facility where aircraft take off and land, with infrastructure for passenger and cargo services.", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: iataCodePropertyType, + }, + { + propertyType: icaoCodePropertyType, + }, + { + propertyType: timezonePropertyType, + }, + { + propertyType: cityPropertyType, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); - const airlineEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Airline", - titlePlural: "Airlines", - icon: "🏦", - description: - "A company that provides air transport services for passengers and/or cargo.", - labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: iataCodePropertyType, - }, - { - propertyType: icaoCodePropertyType, - }, - ], - }, - migrationState, - webShortname: "h", + const airlineEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Airline", + titlePlural: "Airlines", + icon: "🏦", + description: "A company that provides air transport services for passengers and/or cargo.", + labelProperty: blockProtocolPropertyTypes.name.propertyTypeBaseUrl, + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: iataCodePropertyType, + }, + { + propertyType: icaoCodePropertyType, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); - const aircraftEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Aircraft", - titlePlural: "Aircraft", - icon: "🛩️", - description: - "A vehicle designed for air travel, such as an airplane or helicopter.", - labelProperty: registrationNumberPropertyType.metadata.recordId.baseUrl, - properties: [ - { - propertyType: registrationNumberPropertyType, - required: true, - }, - { - propertyType: icaoCodePropertyType, - }, - ], - }, - migrationState, - webShortname: "h", + const aircraftEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Aircraft", + titlePlural: "Aircraft", + icon: "🛩️", + description: "A vehicle designed for air travel, such as an airplane or helicopter.", + labelProperty: registrationNumberPropertyType.metadata.recordId.baseUrl, + properties: [ + { + propertyType: registrationNumberPropertyType, + required: true, + }, + { + propertyType: icaoCodePropertyType, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); /** * Step 3: Create link entity types @@ -856,37 +752,33 @@ const migrate: MigrationFunction = async ({ }, ); - const arrivesAtLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Arrives At", - icon: "🛬", - inverse: { - title: "Arrival For", - }, - description: - "Indicates the airport at which a flight arrives, including arrival-specific details.", - properties: [ - { propertyType: gatePropertyType }, - { propertyType: terminalPropertyType }, - { propertyType: runwayPropertyType }, - { propertyType: baggageClaimPropertyType }, - { propertyType: delayInSecondsPropertyType }, - { propertyType: scheduledGateTimePropertyType }, - { propertyType: estimatedGateTimePropertyType }, - { propertyType: actualGateTimePropertyType }, - { propertyType: scheduledRunwayTimePropertyType }, - { propertyType: estimatedRunwayTimePropertyType }, - { propertyType: actualRunwayTimePropertyType }, - ], + const arrivesAtLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Arrives At", + icon: "🛬", + inverse: { + title: "Arrival For", }, - migrationState, - webShortname: "h", + description: + "Indicates the airport at which a flight arrives, including arrival-specific details.", + properties: [ + { propertyType: gatePropertyType }, + { propertyType: terminalPropertyType }, + { propertyType: runwayPropertyType }, + { propertyType: baggageClaimPropertyType }, + { propertyType: delayInSecondsPropertyType }, + { propertyType: scheduledGateTimePropertyType }, + { propertyType: estimatedGateTimePropertyType }, + { propertyType: actualGateTimePropertyType }, + { propertyType: scheduledRunwayTimePropertyType }, + { propertyType: estimatedRunwayTimePropertyType }, + { propertyType: actualRunwayTimePropertyType }, + ], }, - ); + migrationState, + webShortname: "h", + }); const operatedByLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -930,91 +822,87 @@ const migrate: MigrationFunction = async ({ * Step 4: Create the Flight entity type with links */ - const _flightEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Flight", - titlePlural: "Flights", - icon: "✈️", - description: "A scheduled air transport service between two airports.", - labelProperty: flightNumberPropertyType.metadata.recordId.baseUrl, - properties: [ - { - propertyType: flightNumberPropertyType, - required: true, - }, - { - propertyType: iataCodePropertyType, - }, - { - propertyType: icaoCodePropertyType, - }, - { - propertyType: flightTypePropertyType, - }, - { - propertyType: flightStatusPropertyType, - }, - { - propertyType: flightDatePropertyType, - }, - { - propertyType: codesharePropertyType, - array: true, - }, - { - propertyType: latitudePropertyType, - }, - { - propertyType: longitudePropertyType, - }, - { - propertyType: altitudePropertyType, - }, - { - propertyType: directionPropertyType, - }, - { - propertyType: groundSpeedPropertyType, - }, - { - propertyType: verticalSpeedPropertyType, - }, - { - propertyType: isOnGroundPropertyType, - }, - ], - outgoingLinks: [ - { - linkEntityType: departsFromLinkEntityType, - destinationEntityTypes: [airportEntityType.schema.$id], - minItems: 1, - maxItems: 1, - }, - { - linkEntityType: arrivesAtLinkEntityType, - destinationEntityTypes: [airportEntityType.schema.$id], - minItems: 1, - maxItems: 1, - }, - { - linkEntityType: operatedByLinkEntityType, - destinationEntityTypes: [airlineEntityType.schema.$id], - maxItems: 1, - }, - { - linkEntityType: usesAircraftLinkEntityType, - destinationEntityTypes: [aircraftEntityType.schema.$id], - maxItems: 1, - }, - ], - }, - migrationState, - webShortname: "h", + const _flightEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Flight", + titlePlural: "Flights", + icon: "✈️", + description: "A scheduled air transport service between two airports.", + labelProperty: flightNumberPropertyType.metadata.recordId.baseUrl, + properties: [ + { + propertyType: flightNumberPropertyType, + required: true, + }, + { + propertyType: iataCodePropertyType, + }, + { + propertyType: icaoCodePropertyType, + }, + { + propertyType: flightTypePropertyType, + }, + { + propertyType: flightStatusPropertyType, + }, + { + propertyType: flightDatePropertyType, + }, + { + propertyType: codesharePropertyType, + array: true, + }, + { + propertyType: latitudePropertyType, + }, + { + propertyType: longitudePropertyType, + }, + { + propertyType: altitudePropertyType, + }, + { + propertyType: directionPropertyType, + }, + { + propertyType: groundSpeedPropertyType, + }, + { + propertyType: verticalSpeedPropertyType, + }, + { + propertyType: isOnGroundPropertyType, + }, + ], + outgoingLinks: [ + { + linkEntityType: departsFromLinkEntityType, + destinationEntityTypes: [airportEntityType.schema.$id], + minItems: 1, + maxItems: 1, + }, + { + linkEntityType: arrivesAtLinkEntityType, + destinationEntityTypes: [airportEntityType.schema.$id], + minItems: 1, + maxItems: 1, + }, + { + linkEntityType: operatedByLinkEntityType, + destinationEntityTypes: [airlineEntityType.schema.$id], + maxItems: 1, + }, + { + linkEntityType: usesAircraftLinkEntityType, + destinationEntityTypes: [aircraftEntityType.schema.$id], + maxItems: 1, + }, + ], }, - ); + migrationState, + webShortname: "h", + }); return migrationState; }; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/091-add-petri-nets.dev.migration.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/091-add-petri-nets.dev.migration.ts index fdafe4fbf47..221069c265b 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/091-add-petri-nets.dev.migration.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/migrations/091-add-petri-nets.dev.migration.ts @@ -8,19 +8,14 @@ import { import type { MigrationFunction } from "../types"; -const migrate: MigrationFunction = async ({ - context, - authentication, - migrationState, -}) => { +const migrate: MigrationFunction = async ({ context, authentication, migrationState }) => { const netDefinitionPropertyType = await createSystemPropertyTypeIfNotExists( context, authentication, { propertyTypeDefinition: { title: "Definition Object", - description: - "A definition of something, represented as an opaque JSON object.", + description: "A definition of something, represented as an opaque JSON object.", possibleValues: [{ primitiveDataType: "object" }], }, migrationState, @@ -108,35 +103,31 @@ const migrate: MigrationFunction = async ({ }, ); - const _petriNetEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Petri Net", - description: - "A Petri net is a mathematical model of a system that can be used to represent and analyze complex systems.", - properties: [ - { - propertyType: netDefinitionPropertyType.schema.$id, - required: true, - }, - { - propertyType: titlePropertyTypeId, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: subProcessOfLinkEntityType, - destinationEntityTypes: ["SELF_REFERENCE"], - }, - ], - }, - migrationState, - webShortname: "h", + const _petriNetEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Petri Net", + description: + "A Petri net is a mathematical model of a system that can be used to represent and analyze complex systems.", + properties: [ + { + propertyType: netDefinitionPropertyType.schema.$id, + required: true, + }, + { + propertyType: titlePropertyTypeId, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: subProcessOfLinkEntityType, + destinationEntityTypes: ["SELF_REFERENCE"], + }, + ], }, - ); + migrationState, + webShortname: "h", + }); return migrationState; }; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util.ts index de122819d64..7535f646676 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util.ts @@ -105,10 +105,7 @@ export type PropertyTypeDefinition = { possibleValues: { dataTypeId?: VersionedUrl; primitiveDataType?: PrimitiveDataTypeKey; - propertyTypeObjectProperties?: Record< - string, - ValueOrArray - >; + propertyTypeObjectProperties?: Record>; propertyTypeObjectRequiredProperties?: BaseUrl[]; array?: boolean; }[]; @@ -117,9 +114,7 @@ export type PropertyTypeDefinition = { /** * Helper method for generating a property type schema for the Graph API. */ -export const generateSystemPropertyTypeSchema = ( - params: PropertyTypeDefinition, -): PropertyType => { +export const generateSystemPropertyTypeSchema = (params: PropertyTypeDefinition): PropertyType => { const possibleValues: PropertyValues[] = params.possibleValues.map( ({ array, @@ -141,9 +136,7 @@ export const generateSystemPropertyTypeSchema = ( }; inner = dataTypeReference; } else if (propertyTypeObjectProperties) { - const propertyTypeObject: PropertyValueObject< - ValueOrArray - > = { + const propertyTypeObject: PropertyValueObject> = { type: "object" as const, properties: propertyTypeObjectProperties, required: propertyTypeObjectRequiredProperties @@ -159,9 +152,7 @@ export const generateSystemPropertyTypeSchema = ( // Optionally wrap inner in an array if (array) { - const arrayOfPropertyValues: PropertyValueArray< - OneOfSchema - > = { + const arrayOfPropertyValues: PropertyValueArray> = { type: "array", items: { oneOf: [inner], @@ -227,14 +218,10 @@ export const createSystemDataTypeIfNotExists: ImpureGraphFunction< migrationState.dataTypeVersions[baseUrl] = versionNumber; - const existingDataType = await getDataTypeById( - context.graphApi, - authentication, - { - dataTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ).catch((error: Error) => { + const existingDataType = await getDataTypeById(context.graphApi, authentication, { + dataTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }).catch((error: Error) => { if (error instanceof NotFoundError) { return null; } @@ -250,23 +237,22 @@ export const createSystemDataTypeIfNotExists: ImpureGraphFunction< dataTypeId, }); - const { webId, systemActorMachineId } = await getOrCreateOwningWebId( - context, - webShortname, - ); + const { webId, systemActorMachineId } = await getOrCreateOwningWebId(context, webShortname); if (isSelfHostedInstance) { /** * If this is a self-hosted instance, the system types will be created as external types that don't belong to an in-instance web, * although they will be created by a machine actor associated with an equivalently named web. */ - const { data: dataTypeMetadata } = - await context.graphApi.loadExternalDataType(systemActorMachineId, { + const { data: dataTypeMetadata } = await context.graphApi.loadExternalDataType( + systemActorMachineId, + { // Specify the schema so that self-hosted instances don't need network access to hash.ai schema: dataTypeSchema, conversions, provenance: context.provenance, - }); + }, + ); return { schema: dataTypeSchema, @@ -297,11 +283,7 @@ export const createSystemPropertyTypeIfNotExists: ImpureGraphFunction< propertyTypeDefinition: Omit; } & BaseCreateTypeIfNotExistsParameters, Promise -> = async ( - context, - authentication, - { propertyTypeDefinition, migrationState, webShortname }, -) => { +> = async (context, authentication, { propertyTypeDefinition, migrationState, webShortname }) => { const { title } = propertyTypeDefinition; const baseUrl = generateSystemTypeBaseUrl({ kind: "property-type", @@ -315,11 +297,10 @@ export const createSystemPropertyTypeIfNotExists: ImpureGraphFunction< migrationState.propertyTypeVersions[baseUrl] = versionNumber; - const existingPropertyType = await getPropertyTypeById( - context.graphApi, - authentication, - { propertyTypeId, temporalAxes: currentTimeInstantTemporalAxes }, - ); + const existingPropertyType = await getPropertyTypeById(context.graphApi, authentication, { + propertyTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (existingPropertyType) { return existingPropertyType; @@ -330,22 +311,21 @@ export const createSystemPropertyTypeIfNotExists: ImpureGraphFunction< propertyTypeId, }); - const { webId, systemActorMachineId } = await getOrCreateOwningWebId( - context, - webShortname, - ); + const { webId, systemActorMachineId } = await getOrCreateOwningWebId(context, webShortname); if (isSelfHostedInstance) { /** * If this is a self-hosted instance, the system types will be created as external types that don't belong to an * in-instance web, although they will be created by a machine actor associated with an equivalently named web. */ - const propertyTypeMetadata = - await context.graphApi.loadExternalPropertyType(systemActorMachineId, { + const propertyTypeMetadata = await context.graphApi.loadExternalPropertyType( + systemActorMachineId, + { // Specify the schema so that self-hosted instances don't need network access to hash.ai schema: propertyTypeSchema, provenance: context.provenance, - }); + }, + ); return { schema: propertyTypeSchema, @@ -392,10 +372,7 @@ export type EntityTypeDefinition = { }[]; outgoingLinks?: { linkEntityType: EntityTypeWithMetadata | VersionedUrl; - destinationEntityTypes?: [ - LinkDestinationConstraint, - ...LinkDestinationConstraint[], - ]; + destinationEntityTypes?: [LinkDestinationConstraint, ...LinkDestinationConstraint[]]; minItems?: number; maxItems?: number; }[]; @@ -404,9 +381,7 @@ export type EntityTypeDefinition = { /** * Helper method for generating an entity type schema for the Graph API. */ -export const generateSystemEntityTypeSchema = ( - params: EntityTypeDefinition, -): EntityType => { +export const generateSystemEntityTypeSchema = (params: EntityTypeDefinition): EntityType => { /** @todo - clean this up to be more readable */ const properties = params.properties?.reduce( @@ -418,18 +393,12 @@ export const generateSystemEntityTypeSchema = ( ? { type: "array", items: { - $ref: - typeof propertyType === "object" - ? propertyType.schema.$id - : propertyType, + $ref: typeof propertyType === "object" ? propertyType.schema.$id : propertyType, }, ...(array === true ? {} : array), } : { - $ref: - typeof propertyType === "object" - ? propertyType.schema.$id - : propertyType, + $ref: typeof propertyType === "object" ? propertyType.schema.$id : propertyType, }, }), {}, @@ -450,22 +419,18 @@ export const generateSystemEntityTypeSchema = ( { linkEntityType, destinationEntityTypes, minItems, maxItems }, ): EntityType["links"] => ({ ...prev, - [typeof linkEntityType === "object" - ? linkEntityType.schema.$id - : linkEntityType]: { + [typeof linkEntityType === "object" ? linkEntityType.schema.$id : linkEntityType]: { type: "array", items: destinationEntityTypes ? { - oneOf: destinationEntityTypes.map( - (entityTypeIdOrReference) => ({ - $ref: - entityTypeIdOrReference === "SELF_REFERENCE" - ? params.entityTypeId - : typeof entityTypeIdOrReference === "object" - ? entityTypeIdOrReference.schema.$id - : entityTypeIdOrReference, - }), - ), + oneOf: destinationEntityTypes.map((entityTypeIdOrReference) => ({ + $ref: + entityTypeIdOrReference === "SELF_REFERENCE" + ? params.entityTypeId + : typeof entityTypeIdOrReference === "object" + ? entityTypeIdOrReference.schema.$id + : entityTypeIdOrReference, + })), } : {}, minItems, @@ -475,9 +440,7 @@ export const generateSystemEntityTypeSchema = ( {}, ) ?? undefined; - const allOf = params.allOf - ? atLeastOne(params.allOf.map((url) => ({ $ref: url }))) - : undefined; + const allOf = params.allOf ? atLeastOne(params.allOf.map((url) => ({ $ref: url }))) : undefined; return { $schema: ENTITY_TYPE_META_SCHEMA, @@ -500,11 +463,7 @@ export const createSystemEntityTypeIfNotExists: ImpureGraphFunction< entityTypeDefinition: Omit; } & BaseCreateTypeIfNotExistsParameters, Promise -> = async ( - context, - authentication, - { entityTypeDefinition, migrationState, webShortname }, -) => { +> = async (context, authentication, { entityTypeDefinition, migrationState, webShortname }) => { const { title } = entityTypeDefinition; const baseUrl = generateSystemTypeBaseUrl({ kind: "entity-type", @@ -518,14 +477,10 @@ export const createSystemEntityTypeIfNotExists: ImpureGraphFunction< migrationState.entityTypeVersions[baseUrl] = versionNumber; - const existingEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const existingEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (existingEntityType) { return existingEntityType; @@ -536,10 +491,7 @@ export const createSystemEntityTypeIfNotExists: ImpureGraphFunction< entityTypeId, }); - const { webId, systemActorMachineId } = await getOrCreateOwningWebId( - context, - webShortname, - ); + const { webId, systemActorMachineId } = await getOrCreateOwningWebId(context, webShortname); // The type was missing, try and create it if (isSelfHostedInstance) { @@ -547,14 +499,11 @@ export const createSystemEntityTypeIfNotExists: ImpureGraphFunction< * If this is a self-hosted instance, the system types will be created as external types that don't belong to an in-instance web, * although they will be created by a machine actor associated with an equivalently named web. */ - const entityTypeMetadata = await context.graphApi.loadExternalEntityType( - systemActorMachineId, - { - // Specify the schema so that self-hosted instances don't need network access to hash.ai - schema: entityTypeSchema, - provenance: context.provenance, - }, - ); + const entityTypeMetadata = await context.graphApi.loadExternalEntityType(systemActorMachineId, { + // Specify the schema so that self-hosted instances don't need network access to hash.ai + schema: entityTypeSchema, + provenance: context.provenance, + }); return { schema: entityTypeSchema, @@ -588,13 +537,10 @@ export const getCurrentHashSystemEntityTypeId = ({ }) => { const entityTypeBaseUrl = systemEntityTypes[entityTypeKey].entityTypeBaseUrl; - const entityTypeVersion = - migrationState.entityTypeVersions[entityTypeBaseUrl]; + const entityTypeVersion = migrationState.entityTypeVersions[entityTypeBaseUrl]; if (typeof entityTypeVersion === "undefined") { - throw new Error( - `Expected '${entityTypeKey}' entity type to have been seeded`, - ); + throw new Error(`Expected '${entityTypeKey}' entity type to have been seeded`); } return versionedUrlFromComponents(entityTypeBaseUrl, entityTypeVersion); @@ -607,22 +553,15 @@ export const getCurrentHashLinkEntityTypeId = ({ linkEntityTypeKey: keyof typeof systemLinkEntityTypes; migrationState: MigrationState; }) => { - const linkEntityTypeBaseUrl = - systemLinkEntityTypes[linkEntityTypeKey].linkEntityTypeBaseUrl; + const linkEntityTypeBaseUrl = systemLinkEntityTypes[linkEntityTypeKey].linkEntityTypeBaseUrl; - const linkEntityTypeVersion = - migrationState.entityTypeVersions[linkEntityTypeBaseUrl]; + const linkEntityTypeVersion = migrationState.entityTypeVersions[linkEntityTypeBaseUrl]; if (typeof linkEntityTypeVersion === "undefined") { - throw new Error( - `Expected '${linkEntityTypeKey}' link entity type to have been seeded`, - ); + throw new Error(`Expected '${linkEntityTypeKey}' link entity type to have been seeded`); } - return versionedUrlFromComponents( - linkEntityTypeBaseUrl, - linkEntityTypeVersion, - ); + return versionedUrlFromComponents(linkEntityTypeBaseUrl, linkEntityTypeVersion); }; export const getCurrentHashPropertyTypeId = ({ @@ -632,16 +571,12 @@ export const getCurrentHashPropertyTypeId = ({ propertyTypeKey: keyof typeof systemPropertyTypes; migrationState: MigrationState; }) => { - const propertyTypeBaseUrl = - systemPropertyTypes[propertyTypeKey].propertyTypeBaseUrl; + const propertyTypeBaseUrl = systemPropertyTypes[propertyTypeKey].propertyTypeBaseUrl; - const propertyTypeVersion = - migrationState.propertyTypeVersions[propertyTypeBaseUrl]; + const propertyTypeVersion = migrationState.propertyTypeVersions[propertyTypeBaseUrl]; if (typeof propertyTypeVersion === "undefined") { - throw new Error( - `Expected '${propertyTypeKey}' property type to have been seeded`, - ); + throw new Error(`Expected '${propertyTypeKey}' property type to have been seeded`); } return versionedUrlFromComponents(propertyTypeBaseUrl, propertyTypeVersion); @@ -675,11 +610,7 @@ export const updateSystemEntityType: ImpureGraphFunction< newSchema: EntityType & { $id?: VersionedUrl }; } & BaseUpdateTypeParameters, Promise<{ updatedEntityTypeId: VersionedUrl }> -> = async ( - context, - authentication, - { currentEntityTypeId, newSchema, migrationState }, -) => { +> = async (context, authentication, { currentEntityTypeId, newSchema, migrationState }) => { const { baseUrl, version } = componentsFromVersionedUrl(currentEntityTypeId); const versionInMigrationState = migrationState.entityTypeVersions[baseUrl]; @@ -697,19 +628,12 @@ export const updateSystemEntityType: ImpureGraphFunction< } const nextEntityTypeVersion = incrementOntologyTypeVersion(version); - const nextEntityTypeId = versionedUrlFromComponents( - baseUrl, - nextEntityTypeVersion, - ); + const nextEntityTypeId = versionedUrlFromComponents(baseUrl, nextEntityTypeVersion); - const nextEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: nextEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const nextEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: nextEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (nextEntityType) { migrationState.entityTypeVersions[baseUrl] = nextEntityTypeVersion; @@ -723,10 +647,7 @@ export const updateSystemEntityType: ImpureGraphFunction< const schemaWithConsistentSelfReferences = { ...schemaWithout$id, - links: generateLinkMapWithConsistentSelfReferences( - schemaWithout$id, - currentEntityTypeId, - ), + links: generateLinkMapWithConsistentSelfReferences(schemaWithout$id, currentEntityTypeId), }; const updatedTypeMetadata = isSelfHostedInstance @@ -747,8 +668,7 @@ export const updateSystemEntityType: ImpureGraphFunction< }) .then((resp) => resp.data); - const { version: newVersion } = - updatedTypeMetadata.recordId as unknown as OntologyTypeRecordId; + const { version: newVersion } = updatedTypeMetadata.recordId as unknown as OntologyTypeRecordId; migrationState.entityTypeVersions[baseUrl] = newVersion; @@ -763,14 +683,8 @@ export const updateSystemPropertyType: ImpureGraphFunction< newSchema: UpdatePropertyType & { $id?: VersionedUrl }; } & BaseUpdateTypeParameters, Promise<{ updatedPropertyTypeId: VersionedUrl }> -> = async ( - context, - authentication, - { currentPropertyTypeId, newSchema, migrationState }, -) => { - const { baseUrl, version } = componentsFromVersionedUrl( - currentPropertyTypeId, - ); +> = async (context, authentication, { currentPropertyTypeId, newSchema, migrationState }) => { + const { baseUrl, version } = componentsFromVersionedUrl(currentPropertyTypeId); const versionInMigrationState = migrationState.propertyTypeVersions[baseUrl]; @@ -787,19 +701,12 @@ export const updateSystemPropertyType: ImpureGraphFunction< } const nextPropertyTypeVersion = incrementOntologyTypeVersion(version); - const nextPropertyTypeId = versionedUrlFromComponents( - baseUrl, - nextPropertyTypeVersion, - ); + const nextPropertyTypeId = versionedUrlFromComponents(baseUrl, nextPropertyTypeVersion); - const nextPropertyType = await getPropertyTypeById( - context.graphApi, - authentication, - { - propertyTypeId: nextPropertyTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const nextPropertyType = await getPropertyTypeById(context.graphApi, authentication, { + propertyTypeId: nextPropertyTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (nextPropertyType) { migrationState.propertyTypeVersions[baseUrl] = nextPropertyTypeVersion; @@ -864,14 +771,9 @@ export const upgradeDependenciesInHashEntityType: ImpureGraphFunction< migrationState, }); - const { baseUrl, version } = componentsFromVersionedUrl( - currentDependentEntityTypeId, - ); + const { baseUrl, version } = componentsFromVersionedUrl(currentDependentEntityTypeId); - return versionedUrlFromComponents( - baseUrl, - incrementOntologyTypeVersion(version), - ); + return versionedUrlFromComponents(baseUrl, incrementOntologyTypeVersion(version)); }); for (const dependentEntityTypeKey of dependentEntityTypeKeys) { @@ -880,27 +782,18 @@ export const upgradeDependenciesInHashEntityType: ImpureGraphFunction< migrationState, }); - const currentDependentEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: currentDependentEntityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const currentDependentEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: currentDependentEntityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!currentDependentEntityType) { - throw new Error( - `Expected dependent entity type ${currentDependentEntityTypeId} to exist`, - ); + throw new Error(`Expected dependent entity type ${currentDependentEntityTypeId} to exist`); } const newDependentSchema = upgradeEntityTypeDependencies({ schema: currentDependentEntityType.schema, - upgradedEntityTypeIds: [ - ...upgradedEntityTypeIds, - ...nextDependentEntityTypeIds, - ], + upgradedEntityTypeIds: [...upgradedEntityTypeIds, ...nextDependentEntityTypeIds], }); await updateSystemEntityType(context, authentication, { @@ -981,34 +874,22 @@ export const upgradeEntitiesToNewTypeVersion: ImpureGraphFunction< migrationState: MigrationState; migrateProperties?: Record< BaseUrl, - ( - previousProperties: PropertyObjectWithMetadata, - ) => PropertyObjectWithMetadata + (previousProperties: PropertyObjectWithMetadata) => PropertyObjectWithMetadata >; }, Promise, false, true -> = async ( - context, - authentication, - { entityTypeBaseUrls, migrationState, migrateProperties }, -) => { +> = async (context, authentication, { entityTypeBaseUrls, migrationState, migrateProperties }) => { /** * We have to do this web-by-web because we don't have a single actor that can see all entities in all webs * * @todo figure out what to do about entities which the web machine bot can't view, if we ever create any such entities */ - const { users, orgs } = await getExistingUsersAndOrgs( - context, - authentication, - {}, - ); + const { users, orgs } = await getExistingUsersAndOrgs(context, authentication, {}); for (const webEntity of [...users, ...orgs]) { - const webId = extractWebIdFromEntityId( - webEntity.metadata.recordId.entityId, - ); + const webId = extractWebIdFromEntityId(webEntity.metadata.recordId.entityId); await upgradeWebEntities({ authentication, diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entities.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entities.ts index c3d26b843f4..3f43b49f237 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entities.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entities.ts @@ -1,7 +1,4 @@ -import { - getBreadthFirstEntityTypesAndParents, - getRoots, -} from "@blockprotocol/graph/stdlib"; +import { getBreadthFirstEntityTypesAndParents, getRoots } from "@blockprotocol/graph/stdlib"; import { compareOntologyTypeVersions, componentsFromVersionedUrl, @@ -9,10 +6,7 @@ import { versionedUrlFromComponents, } from "@blockprotocol/type-system"; import { getWebMachineId } from "@local/hash-backend-utils/machine-actors"; -import { - propertyObjectToPatches, - queryEntitySubgraph, -} from "@local/hash-graph-sdk/entity"; +import { propertyObjectToPatches, queryEntitySubgraph } from "@local/hash-graph-sdk/entity"; import { almostFullOntologyResolveDepths, currentTimeInstantTemporalAxes, @@ -48,9 +42,7 @@ export const upgradeWebEntities = async ({ migrationState: MigrationState; migrateProperties?: Record< BaseUrl, - ( - previousProperties: PropertyObjectWithMetadata, - ) => PropertyObjectWithMetadata + (previousProperties: PropertyObjectWithMetadata) => PropertyObjectWithMetadata >; webId: WebId; }) => { @@ -65,47 +57,43 @@ export const upgradeWebEntities = async ({ const webBotAuthentication = { actorId: webBotAccountId as ActorEntityUuid }; - const { subgraph } = await queryEntitySubgraph( - context, - webBotAuthentication, - { - filter: { - all: [ - { - any: entityTypeBaseUrls.map((baseUrl) => ({ - all: [ - { - equal: [ - { path: ["type(inheritanceDepth = 0)", "baseUrl"] }, - { parameter: baseUrl }, - ], - }, - { - less: [ - { path: ["type(inheritanceDepth = 0)", "version"] }, - { parameter: migrationState.entityTypeVersions[baseUrl] }, - ], - }, - ], - })), - }, - { - equal: [ - { path: ["webId"] }, + const { subgraph } = await queryEntitySubgraph(context, webBotAuthentication, { + filter: { + all: [ + { + any: entityTypeBaseUrls.map((baseUrl) => ({ + all: [ + { + equal: [ + { path: ["type(inheritanceDepth = 0)", "baseUrl"] }, + { parameter: baseUrl }, + ], + }, { - parameter: webId, + less: [ + { path: ["type(inheritanceDepth = 0)", "version"] }, + { parameter: migrationState.entityTypeVersions[baseUrl] }, + ], }, ], - }, - ], - }, - graphResolveDepths: almostFullOntologyResolveDepths, - traversalPaths: [], - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts: true, - includePermissions: false, + })), + }, + { + equal: [ + { path: ["webId"] }, + { + parameter: webId, + }, + ], + }, + ], }, - ); + graphResolveDepths: almostFullOntologyResolveDepths, + traversalPaths: [], + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts: true, + includePermissions: false, + }); const existingEntities = getRoots(subgraph); @@ -124,8 +112,7 @@ export const upgradeWebEntities = async ({ * Multiple upgrades may apply to an entity – we apply one at a time. */ for (const baseUrlBeingUpgraded of entityTypeBaseUrls) { - const newVersion = - migrationState.entityTypeVersions[baseUrlBeingUpgraded]; + const newVersion = migrationState.entityTypeVersions[baseUrlBeingUpgraded]; if (typeof newVersion === "undefined") { throw new Error( @@ -139,21 +126,14 @@ export const upgradeWebEntities = async ({ if ( !matchingTypeRecordId || - compareOntologyTypeVersions( - matchingTypeRecordId.version, - newVersion, - ) >= 0 + compareOntologyTypeVersions(matchingTypeRecordId.version, newVersion) >= 0 ) { continue; } - const newEntityTypeId = versionedUrlFromComponents( - baseUrlBeingUpgraded, - newVersion, - ); + const newEntityTypeId = versionedUrlFromComponents(baseUrlBeingUpgraded, newVersion); - const migratePropertiesFunction = - migrateProperties?.[baseUrlBeingUpgraded]; + const migratePropertiesFunction = migrateProperties?.[baseUrlBeingUpgraded]; let updateAuthentication = webBotAuthentication; @@ -161,10 +141,8 @@ export const upgradeWebEntities = async ({ * Determine the actor that should update the entity. */ if ( - baseUrlBeingUpgraded === - systemEntityTypes.userSecret.entityTypeBaseUrl || - baseUrlBeingUpgraded === - systemLinkEntityTypes.usesUserSecret.linkEntityTypeBaseUrl || + baseUrlBeingUpgraded === systemEntityTypes.userSecret.entityTypeBaseUrl || + baseUrlBeingUpgraded === systemLinkEntityTypes.usesUserSecret.linkEntityTypeBaseUrl || baseUrlBeingUpgraded === googleEntityTypes.account.entityTypeBaseUrl ) { /** @@ -173,9 +151,7 @@ export const upgradeWebEntities = async ({ updateAuthentication = { actorId: entity.metadata.provenance.createdById, }; - } else if ( - baseUrlBeingUpgraded === systemEntityTypes.machine.entityTypeBaseUrl - ) { + } else if (baseUrlBeingUpgraded === systemEntityTypes.machine.entityTypeBaseUrl) { /** * If we are updating machine entities, we use the account ID * of the machine user as the actor for the update. @@ -196,8 +172,7 @@ export const upgradeWebEntities = async ({ entity, entityTypeIds: mustHaveAtLeastOne( entity.metadata.entityTypeIds.map((entityTypeId) => { - const { baseUrl, version } = - componentsFromVersionedUrl(entityTypeId); + const { baseUrl, version } = componentsFromVersionedUrl(entityTypeId); if (baseUrl === baseUrlBeingUpgraded) { return newEntityTypeId; @@ -207,9 +182,7 @@ export const upgradeWebEntities = async ({ }), ), propertyPatches: migratePropertiesFunction - ? propertyObjectToPatches( - migratePropertiesFunction(entity.propertiesWithMetadata), - ) + ? propertyObjectToPatches(migratePropertiesFunction(entity.propertiesWithMetadata)) : undefined, }); } diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entity-type-dependencies.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entity-type-dependencies.ts index 0d63f76fb0d..1356a6134dc 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entity-type-dependencies.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/migrate-ontology-types/util/upgrade-entity-type-dependencies.ts @@ -1,11 +1,7 @@ import { atLeastOne, extractBaseUrl } from "@blockprotocol/type-system"; import { typedEntries } from "@local/advanced-types/typed-entries"; -import type { - EntityType, - EntityTypeReference, - VersionedUrl, -} from "@blockprotocol/type-system"; +import type { EntityType, EntityTypeReference, VersionedUrl } from "@blockprotocol/type-system"; export const replaceEntityTypeReference = ({ reference, @@ -17,8 +13,7 @@ export const replaceEntityTypeReference = ({ for (const upgradedEntityTypeId of upgradedEntityTypeIds) { const baseUrlToMatch = extractBaseUrl(upgradedEntityTypeId); - const isDestinationToUpgrade = - extractBaseUrl(reference.$ref) === baseUrlToMatch; + const isDestinationToUpgrade = extractBaseUrl(reference.$ref) === baseUrlToMatch; if (isDestinationToUpgrade) { return { @@ -55,38 +50,39 @@ export const upgradeEntityTypeDependencies = ({ ), ) : undefined, - links: typedEntries(schema.links ?? {}).reduce< - NonNullable - >((accumulator, [uncheckedLinkTypeId, linkSchema]) => { - const oneOf = - "oneOf" in linkSchema.items - ? atLeastOne( - linkSchema.items.oneOf.map((reference) => - replaceEntityTypeReference({ - reference, - upgradedEntityTypeIds, - }), - ), - ) - : undefined; + links: typedEntries(schema.links ?? {}).reduce>( + (accumulator, [uncheckedLinkTypeId, linkSchema]) => { + const oneOf = + "oneOf" in linkSchema.items + ? atLeastOne( + linkSchema.items.oneOf.map((reference) => + replaceEntityTypeReference({ + reference, + upgradedEntityTypeIds, + }), + ), + ) + : undefined; - const schemaWithUpdatedDestinations = { - ...linkSchema, - items: oneOf ? { oneOf } : ({} as Record), - }; + const schemaWithUpdatedDestinations = { + ...linkSchema, + items: oneOf ? { oneOf } : ({} as Record), + }; - let linkTypeId = uncheckedLinkTypeId; - for (const upgradedEntityTypeId of upgradedEntityTypeIds) { - const linkTypeBaseUrl = extractBaseUrl(uncheckedLinkTypeId); - const upgradedEntityTypeBaseUrl = extractBaseUrl(upgradedEntityTypeId); + let linkTypeId = uncheckedLinkTypeId; + for (const upgradedEntityTypeId of upgradedEntityTypeIds) { + const linkTypeBaseUrl = extractBaseUrl(uncheckedLinkTypeId); + const upgradedEntityTypeBaseUrl = extractBaseUrl(upgradedEntityTypeId); - if (linkTypeBaseUrl === upgradedEntityTypeBaseUrl) { - linkTypeId = upgradedEntityTypeId; + if (linkTypeBaseUrl === upgradedEntityTypeBaseUrl) { + linkTypeId = upgradedEntityTypeId; + } } - } - accumulator[linkTypeId] = schemaWithUpdatedDestinations; - return accumulator; - }, {}), + accumulator[linkTypeId] = schemaWithUpdatedDestinations; + return accumulator; + }, + {}, + ), }; }; diff --git a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/system-webs-and-entities.ts b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/system-webs-and-entities.ts index 9266814d936..b1532443e04 100644 --- a/apps/hash-api/src/graph/ensure-system-graph-is-initialized/system-webs-and-entities.ts +++ b/apps/hash-api/src/graph/ensure-system-graph-is-initialized/system-webs-and-entities.ts @@ -6,10 +6,7 @@ import { getMachineEntityByIdentifier, } from "@local/hash-backend-utils/machine-actors"; import { createPolicy, deletePolicyById } from "@local/hash-graph-sdk/policy"; -import { - addActorGroupMember, - createAiActor, -} from "@local/hash-graph-sdk/principal/actor-group"; +import { addActorGroupMember, createAiActor } from "@local/hash-graph-sdk/principal/actor-group"; import { getWebByShortname } from "@local/hash-graph-sdk/principal/web"; import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; @@ -19,11 +16,7 @@ import { createOrg, getOrgByShortname } from "../knowledge/system-types/org"; import { systemAccountId } from "../system-account"; import type { ImpureGraphContext } from "../context-types"; -import type { - MachineId, - VersionedUrl, - WebId, -} from "@blockprotocol/type-system"; +import type { MachineId, VersionedUrl, WebId } from "@blockprotocol/type-system"; import type { blockProtocolDataTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; import type { SystemTypeWebShortname } from "@local/hash-isomorphic-utils/ontology-types"; @@ -63,8 +56,7 @@ export const getOrCreateOwningWebId = async ( }> => { // We only need to resolve this once for each shortname during the seeding process const resolvedWebId = owningWebs[webShortname].webId; - const resolvedSystemActorMachineId = - owningWebs[webShortname].systemActorMachineId; + const resolvedSystemActorMachineId = owningWebs[webShortname].systemActorMachineId; // After this function has been run once, these should exist if (resolvedWebId && resolvedSystemActorMachineId) { @@ -87,9 +79,7 @@ export const getOrCreateOwningWebId = async ( webShortname, ).then((web) => { if (!web) { - throw new NotFoundError( - `Failed to get web for shortname: ${webShortname}`, - ); + throw new NotFoundError(`Failed to get web for shortname: ${webShortname}`); } return web; }); @@ -121,10 +111,7 @@ export const ensureSystemWebEntitiesExist = async ({ machineEntityTypeId?: VersionedUrl; organizationEntityTypeId?: VersionedUrl; }) => { - const { webId, systemActorMachineId } = await getOrCreateOwningWebId( - context, - webShortname, - ); + const { webId, systemActorMachineId } = await getOrCreateOwningWebId(context, webShortname); const authentication = { actorId: systemActorMachineId }; @@ -202,18 +189,12 @@ export const ensureSystemWebEntitiesExist = async ({ * * Also creates other required system entities, such as the HASH AI Assistant. */ -export const ensureSystemEntitiesExist = async (params: { - context: ImpureGraphContext; -}) => { +export const ensureSystemEntitiesExist = async (params: { context: ImpureGraphContext }) => { const { context } = params; - logger.debug( - "Ensuring account group organization and machine entities exist", - ); + logger.debug("Ensuring account group organization and machine entities exist"); - for (const [webShortname, { enabled, name, websiteUrl }] of typedEntries( - owningWebs, - )) { + for (const [webShortname, { enabled, name, websiteUrl }] of typedEntries(owningWebs)) { if (!enabled) { continue; } @@ -236,13 +217,9 @@ export const ensureSystemEntitiesExist = async (params: { /** * Create the HASH _AI_ Machine actor and entity, which is added as needed to webs to run AI-related workflows. */ - const aiMachine = await getMachineEntityByIdentifier( - context, - authentication, - { - identifier: "hash-ai", - }, - ); + const aiMachine = await getMachineEntityByIdentifier(context, authentication, { + identifier: "hash-ai", + }); if (!aiMachine) { const hashWebId = owningWebs.h.webId; if (!hashWebId) { @@ -252,49 +229,41 @@ export const ensureSystemEntitiesExist = async (params: { } const aiIdentifier = "hash-ai"; - const aiAssistantAccountId = await createAiActor( - context.graphApi, - authentication, - { - identifier: aiIdentifier, - }, - ); + const aiAssistantAccountId = await createAiActor(context.graphApi, authentication, { + identifier: aiIdentifier, + }); await addActorGroupMember(context.graphApi, authentication, { actorId: aiAssistantAccountId, actorGroupId: hashWebId, }); - const instantiationPolicyId = await createPolicy( - context.graphApi, - authentication, - { - name: "tmp-ai-assistant-actor-instantiate", - effect: "permit", - principal: { - type: "actor", - actorType: "ai", - id: aiAssistantAccountId, - }, - actions: ["instantiate"], - resource: { - type: "entityType", - filter: { - type: "any", - filters: [ - { - type: "isBaseUrl", - baseUrl: systemEntityTypes.actor.entityTypeBaseUrl, - }, - { - type: "isBaseUrl", - baseUrl: systemEntityTypes.machine.entityTypeBaseUrl, - }, - ], - }, + const instantiationPolicyId = await createPolicy(context.graphApi, authentication, { + name: "tmp-ai-assistant-actor-instantiate", + effect: "permit", + principal: { + type: "actor", + actorType: "ai", + id: aiAssistantAccountId, + }, + actions: ["instantiate"], + resource: { + type: "entityType", + filter: { + type: "any", + filters: [ + { + type: "isBaseUrl", + baseUrl: systemEntityTypes.actor.entityTypeBaseUrl, + }, + { + type: "isBaseUrl", + baseUrl: systemEntityTypes.machine.entityTypeBaseUrl, + }, + ], }, }, - ); + }); await createMachineActorEntity(context, { identifier: aiIdentifier, @@ -304,12 +273,9 @@ export const ensureSystemEntitiesExist = async (params: { displayName: "HASH AI", }); - await deletePolicyById( - context.graphApi, - authentication, - instantiationPolicyId, - { permanent: true }, - ); + await deletePolicyById(context.graphApi, authentication, instantiationPolicyId, { + permanent: true, + }); } }; diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity.ts b/apps/hash-api/src/graph/knowledge/primitive/entity.ts index aaeb2ed650d..8222108a315 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity.ts @@ -37,10 +37,7 @@ import { beforeCreateEntityHooks } from "./entity/before-create-entity-hooks"; import { beforeUpdateEntityHooks } from "./entity/before-update-entity-hooks"; import { createLinkEntity, isEntityLinkEntity } from "./link-entity"; -import type { - EntityDefinition, - LinkedEntityDefinition, -} from "../../../graphql/api-types.gen"; +import type { EntityDefinition, LinkedEntityDefinition } from "../../../graphql/api-types.gen"; import type { ImpureGraphFunction } from "../../context-types"; import type { BaseUrl, @@ -74,36 +71,29 @@ import type { TraversalPath } from "@rust/hash-graph-store/types"; /** @todo: potentially directly export this from the subgraph package */ export type PropertyValue = PropertyObject[BaseUrl]; -type CreateEntityFunction = +type CreateEntityFunction = ImpureGraphFunction< + Omit, "linkData" | "provenance"> & { + outgoingLinks?: (Omit & { + linkData: Omit; + })[]; + }, + Promise> +>; + +type CreateEntityWithLinksFunction = ImpureGraphFunction< Omit, "linkData" | "provenance"> & { - outgoingLinks?: (Omit< - CreateEntityParameters, - "linkData" | "provenance" - > & { - linkData: Omit; - })[]; + linkedEntities?: LinkedEntityDefinition[]; }, - Promise> + Promise>, + false, + true >; -type CreateEntityWithLinksFunction< - Properties extends TypeIdsAndPropertiesForEntity, -> = ImpureGraphFunction< - Omit, "linkData" | "provenance"> & { - linkedEntities?: LinkedEntityDefinition[]; - }, - Promise>, - false, - true ->; - /** * Create an entity. */ -export const createEntity = async < - Properties extends TypeIdsAndPropertiesForEntity, ->( +export const createEntity = async ( ...args: Parameters> ): ReturnType> => { const [context, authentication, params] = args; @@ -116,12 +106,11 @@ export const createEntity = async < for (const beforeCreateHook of beforeCreateEntityHooks) { if (createParams.entityTypeIds.includes(beforeCreateHook.entityTypeId)) { - const { properties: hookReturnedProperties } = - await beforeCreateHook.callback({ - context, - properties, - authentication, - }); + const { properties: hookReturnedProperties } = await beforeCreateHook.callback({ + context, + properties, + authentication, + }); properties = hookReturnedProperties; } @@ -160,15 +149,14 @@ export const createEntity = async < return entity; }; -export const countEntities: ImpureGraphFunction< - CountEntitiesParams, - Promise -> = async ({ graphApi }, { actorId }, params) => - graphApi.countEntities(actorId, params).then(({ data }) => data); +export const countEntities: ImpureGraphFunction> = async ( + { graphApi }, + { actorId }, + params, +) => graphApi.countEntities(actorId, params).then(({ data }) => data); type GetLatestEntityByIdFunction< - Properties extends TypeIdsAndPropertiesForEntity = - TypeIdsAndPropertiesForEntity, + Properties extends TypeIdsAndPropertiesForEntity = TypeIdsAndPropertiesForEntity, > = ImpureGraphFunction< { entityId: EntityId; @@ -196,8 +184,7 @@ type GetLatestEntityByIdFunction< * fault */ export const getLatestEntityById = async < - Properties extends TypeIdsAndPropertiesForEntity = - TypeIdsAndPropertiesForEntity, + Properties extends TypeIdsAndPropertiesForEntity = TypeIdsAndPropertiesForEntity, >( ...args: Parameters> ): ReturnType> => { @@ -335,9 +322,7 @@ export const canUserReadEntity: ImpureGraphFunction< /** * Create an entity along with any new/existing entities specified through links. */ -export const createEntityWithLinks = async < - Properties extends TypeIdsAndPropertiesForEntity, ->( +export const createEntityWithLinks = async ( ...args: Parameters> ): ReturnType> => { const [context, authentication, params] = args; @@ -367,10 +352,7 @@ export const createEntityWithLinks = async < entitiesInTree.map(async (definition) => { const { existingEntityId, parentIndex, meta } = definition; - if ( - !existingEntityId && - (!definition.entityProperties || !definition.entityTypeIds) - ) { + if (!existingEntityId && (!definition.entityProperties || !definition.entityTypeIds)) { throw new Error( `One of existingEntityId or (entityProperties && entityTypeIds) must be provided in linked entity definition: ${JSON.stringify( definition, @@ -391,8 +373,7 @@ export const createEntityWithLinks = async < : await createEntity(context, authentication, { ...createParams, properties: definition.entityProperties!, - entityTypeIds: - definition.entityTypeIds as Properties["entityTypeIds"], + entityTypeIds: definition.entityTypeIds as Properties["entityTypeIds"], }); return { @@ -434,8 +415,7 @@ export const createEntityWithLinks = async < entityTypeIds: [link.meta.linkEntityTypeId], draft: /** If either side of the link is a draft entity, the link entity must be draft also */ - params.draft || - !!extractDraftIdFromEntityId(entity.metadata.recordId.entityId), + params.draft || !!extractDraftIdFromEntityId(entity.metadata.recordId.entityId), }); } }), @@ -444,26 +424,23 @@ export const createEntityWithLinks = async < return rootEntity; }; -type UpdateEntityFunction = - ImpureGraphFunction< - { - entity: HashEntity; - entityTypeIds?: [VersionedUrl, ...VersionedUrl[]]; - propertyPatches?: PropertyPatchOperation[]; - draft?: boolean; - archived?: boolean; - }, - Promise>, - false, - true - >; +type UpdateEntityFunction = ImpureGraphFunction< + { + entity: HashEntity; + entityTypeIds?: [VersionedUrl, ...VersionedUrl[]]; + propertyPatches?: PropertyPatchOperation[]; + draft?: boolean; + archived?: boolean; + }, + Promise>, + false, + true +>; /** * Update an entity. */ -export const updateEntity = async < - Properties extends TypeIdsAndPropertiesForEntity, ->( +export const updateEntity = async ( ...args: Parameters> ): ReturnType> => { const [context, authentication, params] = args; @@ -493,9 +470,7 @@ export const updateEntity = async < */ const additionalAllowedUrls = new Set([enabledFeatureFlagsPropertyBaseUrl]); - const { shortname } = simplifyProperties( - entity.properties as UserProperties, - ); + const { shortname } = simplifyProperties(entity.properties as UserProperties); if (!shortname) { additionalAllowedUrls.add(shortnamePropertyBaseUrl); } @@ -611,12 +586,7 @@ export const getEntityOutgoingLinks: ImpureGraphFunction< }, Promise > = async (context, authentication, params) => { - const { - entityId, - linkEntityTypeVersionedUrl, - rightEntityId, - includeDrafts = false, - } = params; + const { entityId, linkEntityTypeVersionedUrl, rightEntityId, includeDrafts = false } = params; const filter: Filter = { all: [ @@ -750,10 +720,7 @@ export const hasPermissionForEntities: ImpureGraphFunction< HasPermissionForEntitiesParams, { entityIds: EntityId[]; - action: Subtype< - ActionName, - "viewEntity" | "updateEntity" | "archiveEntity" - >; + action: Subtype; temporalAxes: QueryTemporalAxesUnresolved; includeDrafts: boolean; } @@ -762,18 +729,12 @@ export const hasPermissionForEntities: ImpureGraphFunction< > = async ({ graphApi }, { actorId }, params) => graphApi .hasPermissionForEntities(actorId, params) - .then( - ({ data }) => - data as Record, - ); + .then(({ data }) => data as Record); export const checkEntityPermission: ImpureGraphFunction< { entityId: EntityId; - permission: Subtype< - ActionName, - "viewEntity" | "updateEntity" | "archiveEntity" - >; + permission: Subtype; }, Promise > = async (context, authentication, params) => @@ -814,9 +775,7 @@ export const checkPermissionsOnEntity: ImpureGraphFunction< { actorId }, { actorId, - actorGroupId: extractEntityUuidFromEntityId(entityId) as - | WebId - | TeamId, + actorGroupId: extractEntityUuidFromEntityId(entityId) as WebId | TeamId, }, ).then((role) => role === "administrator") : null, @@ -854,13 +813,8 @@ export const checkPermissionsOnEntitiesInSubgraph: ImpureGraphFunction< const userPermissionsOnEntities: UserPermissionsOnEntities = {}; await Promise.all( entities.map(async (entity) => { - const permissions = await checkPermissionsOnEntity( - graphContext, - authentication, - { entity }, - ); - userPermissionsOnEntities[entity.metadata.recordId.entityId] = - permissions; + const permissions = await checkPermissionsOnEntity(graphContext, authentication, { entity }); + userPermissionsOnEntities[entity.metadata.recordId.entityId] = permissions; }), ); diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/after-create-entity-hooks.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/after-create-entity-hooks.ts index e12e8bd6403..171c9c3bcb6 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/after-create-entity-hooks.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/after-create-entity-hooks.ts @@ -8,10 +8,7 @@ import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-proper import { isProdEnv } from "../../../../lib/env-config"; import { createOrUpdateMailchimpUser } from "../../../../mailchimp"; -import { - getBlockCollectionByBlock, - getBlockFromEntity, -} from "../../system-types/block"; +import { getBlockCollectionByBlock, getBlockFromEntity } from "../../system-types/block"; import { getCommentAncestorBlock, getCommentAuthor, @@ -24,18 +21,12 @@ import { getMentionNotification, } from "../../system-types/notification"; import { getPageFromEntity } from "../../system-types/page"; -import { - getMentionedUsersInTextualContent, - getTextById, -} from "../../system-types/text"; +import { getMentionedUsersInTextualContent, getTextById } from "../../system-types/text"; import { getUser } from "../../system-types/user"; import { checkPermissionsOnEntity } from "../entity"; import { getTextUpdateOccurredIn } from "./shared/mention-notification"; -import type { - AfterCreateEntityHook, - AfterCreateEntityHookCallback, -} from "./create-entity-hooks"; +import type { AfterCreateEntityHook, AfterCreateEntityHookCallback } from "./create-entity-hooks"; import type { EntityUuid, WebId } from "@blockprotocol/type-system"; import type { UserProperties } from "@local/hash-isomorphic-utils/system-types/user"; @@ -57,17 +48,11 @@ const commentCreateHookCallback: AfterCreateEntityHookCallback = async ({ }); // If the parent of the comment is a block, check if we need to create a comment notification - if ( - commentParent.metadata.entityTypeIds.includes( - systemEntityTypes.block.entityTypeId, - ) - ) { + if (commentParent.metadata.entityTypeIds.includes(systemEntityTypes.block.entityTypeId)) { const parentBlock = getBlockFromEntity({ entity: commentParent }); - const blockCollectionEntity = await getBlockCollectionByBlock( - context, - authentication, - { block: parentBlock }, - ); + const blockCollectionEntity = await getBlockCollectionByBlock(context, authentication, { + block: parentBlock, + }); if ( blockCollectionEntity && @@ -77,8 +62,7 @@ const commentCreateHookCallback: AfterCreateEntityHookCallback = async ({ entity: blockCollectionEntity, }); - const pageAuthorAccountId = - occurredInEntity.entity.metadata.provenance.createdById; + const pageAuthorAccountId = occurredInEntity.entity.metadata.provenance.createdById; const pageAuthorEntityId = entityIdFromComponents( pageAuthorAccountId as WebId, @@ -105,10 +89,7 @@ const commentCreateHookCallback: AfterCreateEntityHookCallback = async ({ // If the comment author is not the page creator, and the page // creator can view the page, then create a page comment notification - if ( - commentAuthor.accountId !== pageAuthor.accountId && - pageAuthorCanViewPage - ) { + if (commentAuthor.accountId !== pageAuthor.accountId && pageAuthorCanViewPage) { await createCommentNotification( context, { actorId: pageAuthor.accountId }, @@ -124,23 +105,17 @@ const commentCreateHookCallback: AfterCreateEntityHookCallback = async ({ } // If the parent is another comment check if we need to create a comment reply notification } else if ( - commentParent.metadata.entityTypeIds.includes( - systemEntityTypes.comment.entityTypeId, - ) + commentParent.metadata.entityTypeIds.includes(systemEntityTypes.comment.entityTypeId) ) { const parentComment = getCommentFromEntity({ entity: commentParent }); - const ancestorBlock = await getCommentAncestorBlock( - context, - authentication, - { commentEntityId: parentComment.entity.metadata.recordId.entityId }, - ); + const ancestorBlock = await getCommentAncestorBlock(context, authentication, { + commentEntityId: parentComment.entity.metadata.recordId.entityId, + }); - const blockCollectionEntity = await getBlockCollectionByBlock( - context, - authentication, - { block: ancestorBlock }, - ); + const blockCollectionEntity = await getBlockCollectionByBlock(context, authentication, { + block: ancestorBlock, + }); if ( blockCollectionEntity && @@ -159,12 +134,11 @@ const commentCreateHookCallback: AfterCreateEntityHookCallback = async ({ }), ]); - const { view: parentCommentAuthorCanViewPage } = - await checkPermissionsOnEntity( - context, - { actorId: parentCommentAuthor.accountId }, - { entity: occurredInEntity.entity }, - ); + const { view: parentCommentAuthorCanViewPage } = await checkPermissionsOnEntity( + context, + { actorId: parentCommentAuthor.accountId }, + { entity: occurredInEntity.entity }, + ); // If the comment author is not the parent comment author, and the // parent comment author can view the page, then create a comment @@ -206,10 +180,13 @@ const hasTextCreateHookCallback: AfterCreateEntityHookCallback = async ({ entityId: entity.linkData!.rightEntityId, }); - const { occurredInComment, occurredInEntity, occurredInBlock } = - await getTextUpdateOccurredIn(context, authentication, { + const { occurredInComment, occurredInEntity, occurredInBlock } = await getTextUpdateOccurredIn( + context, + authentication, + { text, - }); + }, + ); if (!occurredInEntity || !occurredInBlock) { return undefined; @@ -217,11 +194,9 @@ const hasTextCreateHookCallback: AfterCreateEntityHookCallback = async ({ const { textualContent } = text; - const mentionedUsers = await getMentionedUsersInTextualContent( - context, - authentication, - { textualContent }, - ); + const mentionedUsers = await getMentionedUsersInTextualContent(context, authentication, { + textualContent, + }); const triggeredByUserEntityId = entityIdFromComponents( authentication.actorId as WebId, @@ -240,12 +215,11 @@ const hasTextCreateHookCallback: AfterCreateEntityHookCallback = async ({ ...mentionedUsers .filter((user) => user.accountId !== triggeredByUser.accountId) .map(async (mentionedUser) => { - const { view: mentionedUserCanViewPage } = - await checkPermissionsOnEntity( - context, - { actorId: mentionedUser.accountId }, - { entity: occurredInEntity.entity }, - ); + const { view: mentionedUserCanViewPage } = await checkPermissionsOnEntity( + context, + { actorId: mentionedUser.accountId }, + { entity: occurredInEntity.entity }, + ); if (!mentionedUserCanViewPage) { return; @@ -284,9 +258,7 @@ const hasTextCreateHookCallback: AfterCreateEntityHookCallback = async ({ ]); }; -const userCreateHookCallback: AfterCreateEntityHookCallback = async ({ - entity, -}) => { +const userCreateHookCallback: AfterCreateEntityHookCallback = async ({ entity }) => { if (isProdEnv) { const { email: emails, diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/file-document-after-update-entity-hook-callback.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/file-document-after-update-entity-hook-callback.ts index 0a7c099b21b..f975a286b85 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/file-document-after-update-entity-hook-callback.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/file-document-after-update-entity-hook-callback.ts @@ -1,13 +1,7 @@ import { extractWebIdFromEntityId } from "@blockprotocol/type-system"; -import { - isStorageType, - storageProviderLookup, -} from "@local/hash-backend-utils/file-storage"; +import { isStorageType, storageProviderLookup } from "@local/hash-backend-utils/file-storage"; import { getWebMachineId } from "@local/hash-backend-utils/machine-actors"; -import { - getDefinedPropertyFromPatchesGetter, - type HashEntity, -} from "@local/hash-graph-sdk/entity"; +import { getDefinedPropertyFromPatchesGetter, type HashEntity } from "@local/hash-graph-sdk/entity"; import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-properties"; @@ -28,22 +22,13 @@ export const entityTypesToParseTextFrom: VersionedUrl[] = [ type FileEntityToParse = DOCXDocument | PDFDocument | PPTXPresentation; export const parseTextFromFileAfterUpdateEntityHookCallback: AfterUpdateEntityHookCallback = - async ({ - previousEntity, - propertyPatches, - context, - authentication, - updatedEntity, - }) => { + async ({ previousEntity, propertyPatches, context, authentication, updatedEntity }) => { const { temporalClient } = context; - const previousEntityProperties = - previousEntity as HashEntity; + const previousEntityProperties = previousEntity as HashEntity; const getNewValueForPath = - getDefinedPropertyFromPatchesGetter( - propertyPatches, - ); + getDefinedPropertyFromPatchesGetter(propertyPatches); const newFileStorageKey = getNewValueForPath( "https://hash.ai/@h/types/property-type/file-storage-key/", @@ -54,10 +39,9 @@ export const parseTextFromFileAfterUpdateEntityHookCallback: AfterUpdateEntityHo "https://hash.ai/@h/types/property-type/file-storage-key/" ]; - const { textualContent, fileStorageProvider, uploadCompletedAt } = - simplifyProperties( - updatedEntity.properties as FileEntityToParse["properties"], - ); + const { textualContent, fileStorageProvider, uploadCompletedAt } = simplifyProperties( + updatedEntity.properties as FileEntityToParse["properties"], + ); if (textualContent && newFileStorageKey === oldFileStorageKey) { /** @@ -89,38 +73,35 @@ export const parseTextFromFileAfterUpdateEntityHookCallback: AfterUpdateEntityHo const workflowId = `${updatedEntity.metadata.recordId.editionId}-parse-text-from-file-workflow-id`; - const fileEntityWebId = extractWebIdFromEntityId( - updatedEntity.metadata.recordId.entityId, - ); + const fileEntityWebId = extractWebIdFromEntityId(updatedEntity.metadata.recordId.entityId); const webMachineActorId = await getWebMachineId(context, authentication, { webId: fileEntityWebId, }).then((maybeMachineId) => { if (!maybeMachineId) { - throw new Error( - `Failed to get web bot account ID for web ID: ${fileEntityWebId}`, - ); + throw new Error(`Failed to get web bot account ID for web ID: ${fileEntityWebId}`); } return maybeMachineId; }); try { - await temporalClient.workflow.execute< - (params: ParseTextFromFileParams) => Promise - >("parseTextFromFile", { - taskQueue: "ai", - args: [ - { - presignedFileDownloadUrl, - fileEntity: updatedEntity.toJSON(), - webMachineActorId, + await temporalClient.workflow.execute<(params: ParseTextFromFileParams) => Promise>( + "parseTextFromFile", + { + taskQueue: "ai", + args: [ + { + presignedFileDownloadUrl, + fileEntity: updatedEntity.toJSON(), + webMachineActorId, + }, + ], + workflowId, + retry: { + maximumAttempts: 1, }, - ], - workflowId, - retry: { - maximumAttempts: 1, }, - }); + ); } catch { /** @todo: figure out whether this should be logged */ return undefined; diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/text-after-update-entity-hook-callback.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/text-after-update-entity-hook-callback.ts index 420547003d9..2e7549da659 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/text-after-update-entity-hook-callback.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/text-after-update-entity-hook-callback.ts @@ -6,10 +6,7 @@ import { createMentionNotification, getMentionNotification, } from "../../../system-types/notification"; -import { - getMentionedUsersInTextualContent, - getTextFromEntity, -} from "../../../system-types/text"; +import { getMentionedUsersInTextualContent, getTextFromEntity } from "../../../system-types/text"; import { getUser } from "../../../system-types/user"; import { checkPermissionsOnEntity } from "../../entity"; import { getTextUpdateOccurredIn } from "../shared/mention-notification"; @@ -25,83 +22,122 @@ import type { TextToken } from "@local/hash-isomorphic-utils/types"; * - the `Text` entity is in a page * - the `Text` entity is in a comment that's on a page */ -export const textAfterUpdateEntityHookCallback: AfterUpdateEntityHookCallback = - async ({ previousEntity, propertyPatches, authentication, context }) => { - const getNewValueForPath = - getDefinedPropertyFromPatchesGetter(propertyPatches); - - const newTextValue = getNewValueForPath( - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/", - ); - - if (!newTextValue || typeof newTextValue === "string") { - return; - } - - const updatedTextualContent = newTextValue as TextToken[]; - - const text = getTextFromEntity({ entity: previousEntity }); - - const { occurredInComment, occurredInEntity, occurredInBlock } = - await getTextUpdateOccurredIn(context, authentication, { - text, - }); - - if (!occurredInEntity || !occurredInBlock) { - return; - } - - const previousTextualContent = text.textualContent; - - const [previousMentionedUsers, updatedMentionedUsers] = await Promise.all([ - getMentionedUsersInTextualContent(context, authentication, { - textualContent: previousTextualContent, - }), - getMentionedUsersInTextualContent(context, authentication, { - textualContent: updatedTextualContent, - }), - ]); - - const addedMentionedUsers = updatedMentionedUsers.filter( - (user) => - !previousMentionedUsers.some( - (previousUser) => - previousUser.entity.metadata.recordId.entityId === - user.entity.metadata.recordId.entityId, - ), - ); - - const removedMentionedUsers = previousMentionedUsers.filter( - (previousUser) => - !updatedMentionedUsers.some( - (user) => - user.entity.metadata.recordId.entityId === - previousUser.entity.metadata.recordId.entityId, - ), - ); - - const triggeredByUserEntityId = entityIdFromComponents( - authentication.actorId as WebId, - authentication.actorId as string as EntityUuid, +export const textAfterUpdateEntityHookCallback: AfterUpdateEntityHookCallback = async ({ + previousEntity, + propertyPatches, + authentication, + context, +}) => { + const getNewValueForPath = getDefinedPropertyFromPatchesGetter(propertyPatches); + + const newTextValue = getNewValueForPath( + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/", + ); + + if (!newTextValue || typeof newTextValue === "string") { + return; + } + + const updatedTextualContent = newTextValue as TextToken[]; + + const text = getTextFromEntity({ entity: previousEntity }); + + const { occurredInComment, occurredInEntity, occurredInBlock } = await getTextUpdateOccurredIn( + context, + authentication, + { + text, + }, + ); + + if (!occurredInEntity || !occurredInBlock) { + return; + } + + const previousTextualContent = text.textualContent; + + const [previousMentionedUsers, updatedMentionedUsers] = await Promise.all([ + getMentionedUsersInTextualContent(context, authentication, { + textualContent: previousTextualContent, + }), + getMentionedUsersInTextualContent(context, authentication, { + textualContent: updatedTextualContent, + }), + ]); + + const addedMentionedUsers = updatedMentionedUsers.filter( + (user) => + !previousMentionedUsers.some( + (previousUser) => + previousUser.entity.metadata.recordId.entityId === user.entity.metadata.recordId.entityId, + ), + ); + + const removedMentionedUsers = previousMentionedUsers.filter( + (previousUser) => + !updatedMentionedUsers.some( + (user) => + user.entity.metadata.recordId.entityId === previousUser.entity.metadata.recordId.entityId, + ), + ); + + const triggeredByUserEntityId = entityIdFromComponents( + authentication.actorId as WebId, + authentication.actorId as string as EntityUuid, + ); + + const triggeredByUser = await getUser(context, authentication, { + entityId: triggeredByUserEntityId, + }); + + if (!triggeredByUser) { + throw new Error( + `User with entityId ${triggeredByUserEntityId} doesn't exist or cannot be accessed by requesting user.`, ); + } + + await Promise.all([ + ...removedMentionedUsers.map(async (removedMentionedUser) => { + const existingNotification = await getMentionNotification( + context, + { actorId: removedMentionedUser.accountId }, + { + recipient: removedMentionedUser, + triggeredByUser, + occurredInEntity, + occurredInComment, + occurredInBlock, + occurredInText: text, + }, + ); - const triggeredByUser = await getUser(context, authentication, { - entityId: triggeredByUserEntityId, - }); + if (existingNotification) { + await archiveNotification( + context, + { actorId: removedMentionedUser.accountId }, + { notification: existingNotification }, + ); + } + }), + ...addedMentionedUsers + .filter((addedMentionedUser) => triggeredByUser.accountId !== addedMentionedUser.accountId) + .map(async (addedMentionedUser) => { + const { view: mentionedUserCanViewPage } = await checkPermissionsOnEntity( + context, + { actorId: addedMentionedUser.accountId }, + { entity: occurredInEntity.entity }, + ); - if (!triggeredByUser) { - throw new Error( - `User with entityId ${triggeredByUserEntityId} doesn't exist or cannot be accessed by requesting user.`, - ); - } + if (!mentionedUserCanViewPage) { + return; + } - await Promise.all([ - ...removedMentionedUsers.map(async (removedMentionedUser) => { const existingNotification = await getMentionNotification( context, - { actorId: removedMentionedUser.accountId }, + /** @todo: use authentication of machine user instead */ + { actorId: addedMentionedUser.accountId }, { - recipient: removedMentionedUser, + recipient: addedMentionedUser, triggeredByUser, occurredInEntity, occurredInComment, @@ -110,60 +146,21 @@ export const textAfterUpdateEntityHookCallback: AfterUpdateEntityHookCallback = }, ); - if (existingNotification) { - await archiveNotification( - context, - { actorId: removedMentionedUser.accountId }, - { notification: existingNotification }, - ); - } - }), - ...addedMentionedUsers - .filter( - (addedMentionedUser) => - triggeredByUser.accountId !== addedMentionedUser.accountId, - ) - .map(async (addedMentionedUser) => { - const { view: mentionedUserCanViewPage } = - await checkPermissionsOnEntity( - context, - { actorId: addedMentionedUser.accountId }, - { entity: occurredInEntity.entity }, - ); - - if (!mentionedUserCanViewPage) { - return; - } - - const existingNotification = await getMentionNotification( + if (!existingNotification) { + await createMentionNotification( context, /** @todo: use authentication of machine user instead */ { actorId: addedMentionedUser.accountId }, { - recipient: addedMentionedUser, - triggeredByUser, + webId: addedMentionedUser.accountId, occurredInEntity, - occurredInComment, occurredInBlock, + occurredInComment, occurredInText: text, + triggeredByUser, }, ); - - if (!existingNotification) { - await createMentionNotification( - context, - /** @todo: use authentication of machine user instead */ - { actorId: addedMentionedUser.accountId }, - { - webId: addedMentionedUser.accountId, - occurredInEntity, - occurredInBlock, - occurredInComment, - occurredInText: text, - triggeredByUser, - }, - ); - } - }), - ]); - }; + } + }), + ]); +}; diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/user-after-update-entity-hook.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/user-after-update-entity-hook.ts index ed31a534fb9..33ad061ee8c 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/user-after-update-entity-hook.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/after-update-entity-hooks/user-after-update-entity-hook.ts @@ -3,57 +3,53 @@ import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-proper import { isProdEnv } from "../../../../../lib/env-config"; import { createOrUpdateMailchimpUser } from "../../../../../mailchimp"; -import { - getUserFromEntity, - updateUserKratosIdentityTraits, -} from "../../../system-types/user"; +import { getUserFromEntity, updateUserKratosIdentityTraits } from "../../../system-types/user"; import type { AfterUpdateEntityHookCallback } from "../update-entity-hooks"; import type { UserProperties } from "@local/hash-isomorphic-utils/system-types/user"; -export const userAfterUpdateEntityHookCallback: AfterUpdateEntityHookCallback = - async ({ context, propertyPatches, updatedEntity }) => { - const getNewValueForPath = - getDefinedPropertyFromPatchesGetter(propertyPatches); - - const updatedEmails = getNewValueForPath( - "https://hash.ai/@h/types/property-type/email/", - ); - - const { shortname, displayName, email } = simplifyProperties( - updatedEntity.properties as UserProperties, - ); - - const hasEmailChanged = - updatedEmails && - updatedEmails.sort().join(",") !== email.sort().join(","); - - if (hasEmailChanged && isProdEnv) { - /** - * @todo H-4936: when we allow users to have more than one email, come up with - * a better way of determining which to use for mailchimp. - */ - const newEmail = updatedEmails[0]; - - await createOrUpdateMailchimpUser({ - email: newEmail, - shortname, - displayName, - }); - } - - const user = getUserFromEntity({ entity: updatedEntity }); - - if (hasEmailChanged) { - await updateUserKratosIdentityTraits( - context, - { actorId: user.accountId }, - { - user, - updatedTraits: { - emails: updatedEmails, - }, +export const userAfterUpdateEntityHookCallback: AfterUpdateEntityHookCallback = async ({ + context, + propertyPatches, + updatedEntity, +}) => { + const getNewValueForPath = getDefinedPropertyFromPatchesGetter(propertyPatches); + + const updatedEmails = getNewValueForPath("https://hash.ai/@h/types/property-type/email/"); + + const { shortname, displayName, email } = simplifyProperties( + updatedEntity.properties as UserProperties, + ); + + const hasEmailChanged = + updatedEmails && updatedEmails.sort().join(",") !== email.sort().join(","); + + if (hasEmailChanged && isProdEnv) { + /** + * @todo H-4936: when we allow users to have more than one email, come up with + * a better way of determining which to use for mailchimp. + */ + const newEmail = updatedEmails[0]; + + await createOrUpdateMailchimpUser({ + email: newEmail, + shortname, + displayName, + }); + } + + const user = getUserFromEntity({ entity: updatedEntity }); + + if (hasEmailChanged) { + await updateUserKratosIdentityTraits( + context, + { actorId: user.accountId }, + { + user, + updatedTraits: { + emails: updatedEmails, }, - ); - } - }; + }, + ); + } +}; diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/before-update-entity-hooks/user-before-update-entity-hook-callback.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/before-update-entity-hooks/user-before-update-entity-hook-callback.ts index 4a0df76019c..66916c1aafb 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/before-update-entity-hooks/user-before-update-entity-hook-callback.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/before-update-entity-hooks/user-before-update-entity-hook-callback.ts @@ -26,18 +26,11 @@ import { shortnameMaximumLength, shortnameMinimumLength, } from "../../../system-types/account.fields"; -import { - getUserFromEntity, - getUserVerifiedEmails, -} from "../../../system-types/user"; +import { getUserFromEntity, getUserVerifiedEmails } from "../../../system-types/user"; import type { ImpureGraphContext } from "../../../../context-types"; import type { BeforeUpdateEntityHookCallback } from "../update-entity-hooks"; -import type { - ActorEntityUuid, - BaseUrl, - WebId, -} from "@blockprotocol/type-system"; +import type { ActorEntityUuid, BaseUrl, WebId } from "@blockprotocol/type-system"; import type { UserProperties } from "@local/hash-isomorphic-utils/system-types/user"; /** @@ -57,9 +50,7 @@ const validateAccountShortname = async ( shortname: string, ) => { if (shortnameContainsInvalidCharacter({ shortname })) { - throw Error.badUserInput( - "Shortname may only contain letters, numbers, - or _", - ); + throw Error.badUserInput("Shortname may only contain letters, numbers, - or _"); } if (shortname[0] === "-") { @@ -81,181 +72,151 @@ const validateAccountShortname = async ( } }; -export const userBeforeEntityUpdateHookCallback: BeforeUpdateEntityHookCallback = - async ({ previousEntity, propertyPatches, context, authentication }) => { - const user = getUserFromEntity({ entity: previousEntity }); - - /** - * Block any property patches that aren't in the whitelist and don't have special handling. - * This is a defense-in-depth check – the Entity SDK's patch method also enforces - * allowed properties, but this hook guards the Node API path as well. - */ - for (const patch of propertyPatches) { - const targetBaseUrl = patch.path[0] as BaseUrl | undefined; - if (targetBaseUrl === undefined) { - throw Error.badUserInput( - "Cannot replace the entire property object on a user entity", - ); - } - - if ( - !userSelfUpdatablePropertyBaseUrls.has(targetBaseUrl) && - !speciallyHandledPropertyBaseUrls.has(targetBaseUrl) - ) { - throw Error.badUserInput( - `Cannot update property '${targetBaseUrl}' on a user entity`, - ); - } +export const userBeforeEntityUpdateHookCallback: BeforeUpdateEntityHookCallback = async ({ + previousEntity, + propertyPatches, + context, + authentication, +}) => { + const user = getUserFromEntity({ entity: previousEntity }); + + /** + * Block any property patches that aren't in the whitelist and don't have special handling. + * This is a defense-in-depth check – the Entity SDK's patch method also enforces + * allowed properties, but this hook guards the Node API path as well. + */ + for (const patch of propertyPatches) { + const targetBaseUrl = patch.path[0] as BaseUrl | undefined; + if (targetBaseUrl === undefined) { + throw Error.badUserInput("Cannot replace the entire property object on a user entity"); } - const isShortnameRemoved = isValueRemovedByPatches({ - baseUrl: "https://hash.ai/@h/types/property-type/shortname/", - propertyPatches, - }); - if (isShortnameRemoved) { - throw Error.badUserInput("Cannot unset shortname"); + if ( + !userSelfUpdatablePropertyBaseUrls.has(targetBaseUrl) && + !speciallyHandledPropertyBaseUrls.has(targetBaseUrl) + ) { + throw Error.badUserInput(`Cannot update property '${targetBaseUrl}' on a user entity`); } + } - const isEmailRemoved = isValueRemovedByPatches({ - baseUrl: "https://hash.ai/@h/types/property-type/email/", - propertyPatches, - }); - if (isEmailRemoved) { - throw Error.badUserInput("Cannot unset email"); - } + const isShortnameRemoved = isValueRemovedByPatches({ + baseUrl: "https://hash.ai/@h/types/property-type/shortname/", + propertyPatches, + }); + if (isShortnameRemoved) { + throw Error.badUserInput("Cannot unset shortname"); + } - const getNewValueForPath = - getDefinedPropertyFromPatchesGetter(propertyPatches); + const isEmailRemoved = isValueRemovedByPatches({ + baseUrl: "https://hash.ai/@h/types/property-type/email/", + propertyPatches, + }); + if (isEmailRemoved) { + throw Error.badUserInput("Cannot unset email"); + } - const currentEmails = user.emails; + const getNewValueForPath = getDefinedPropertyFromPatchesGetter(propertyPatches); - const updatedEmails = getNewValueForPath( - "https://hash.ai/@h/types/property-type/email/", - ); + const currentEmails = user.emails; - if ( - updatedEmails && - updatedEmails.sort().join(",") !== currentEmails.sort().join(",") - ) { - throw Error.badUserInput("Cannot change email"); - } + const updatedEmails = getNewValueForPath("https://hash.ai/@h/types/property-type/email/"); - const currentFeatureFlags = user.enabledFeatureFlags; + if (updatedEmails && updatedEmails.sort().join(",") !== currentEmails.sort().join(",")) { + throw Error.badUserInput("Cannot change email"); + } - const updatedFeatureFlags = getNewValueForPath( - "https://hash.ai/@h/types/property-type/enabled-feature-flags/", - ); + const currentFeatureFlags = user.enabledFeatureFlags; - if ( - updatedFeatureFlags && - updatedFeatureFlags.sort().join(",") !== - currentFeatureFlags.sort().join(",") && - !(await isUserHashInstanceAdmin(context, authentication, { - userAccountId: authentication.actorId, - })) - ) { - throw Error.badUserInput("Cannot change feature flags"); - } + const updatedFeatureFlags = getNewValueForPath( + "https://hash.ai/@h/types/property-type/enabled-feature-flags/", + ); - const currentShortname = user.shortname; + if ( + updatedFeatureFlags && + updatedFeatureFlags.sort().join(",") !== currentFeatureFlags.sort().join(",") && + !(await isUserHashInstanceAdmin(context, authentication, { + userAccountId: authentication.actorId, + })) + ) { + throw Error.badUserInput("Cannot change feature flags"); + } - const updatedShortname = getNewValueForPath( - "https://hash.ai/@h/types/property-type/shortname/", - ); + const currentShortname = user.shortname; - const updatedDisplayName = getNewValueForPath( - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/", - ); + const updatedShortname = getNewValueForPath("https://hash.ai/@h/types/property-type/shortname/"); - if (updatedShortname) { - if ( - currentShortname && - currentShortname.toLowerCase() !== updatedShortname.toLowerCase() - ) { - throw Error.badUserInput("Cannot change shortname"); - } + const updatedDisplayName = getNewValueForPath( + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/", + ); - if (!currentShortname) { - await validateAccountShortname( - context, - { actorId: user.accountId }, - updatedShortname, - ); - } + if (updatedShortname) { + if (currentShortname && currentShortname.toLowerCase() !== updatedShortname.toLowerCase()) { + throw Error.badUserInput("Cannot change shortname"); } - const isDisplayNameRemoved = isValueRemovedByPatches({ - baseUrl: - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/", - propertyPatches, - }); - if ( - (updatedDisplayName !== undefined && !updatedDisplayName) || - isDisplayNameRemoved - ) { - throw new GraphQLError("Cannot unset display name"); + if (!currentShortname) { + await validateAccountShortname(context, { actorId: user.accountId }, updatedShortname); } + } - const isIncompleteUser = !user.isAccountSignupComplete; - - if (isIncompleteUser && (updatedShortname || updatedDisplayName)) { - /** - * If the user doesn't have access to the HASH instance, - * we need to forbid them from completing account signup - * and prevent them from receiving ownership of the web. - */ - const accessResult = await userHasAccessToHash( - context, - authentication, - user, - ); + const isDisplayNameRemoved = isValueRemovedByPatches({ + baseUrl: "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/", + propertyPatches, + }); + if ((updatedDisplayName !== undefined && !updatedDisplayName) || isDisplayNameRemoved) { + throw new GraphQLError("Cannot unset display name"); + } - if (!accessResult.allowed) { - throw Error.forbidden( - "The user does not have access to the HASH instance, and therefore cannot complete account signup.", - ); - } + const isIncompleteUser = !user.isAccountSignupComplete; - const onlyForEmails = accessResult.onlyForEmails ?? []; + if (isIncompleteUser && (updatedShortname || updatedDisplayName)) { + /** + * If the user doesn't have access to the HASH instance, + * we need to forbid them from completing account signup + * and prevent them from receiving ownership of the web. + */ + const accessResult = await userHasAccessToHash(context, authentication, user); - if (onlyForEmails.length > 0) { - const verifiedEmails = await getUserVerifiedEmails( - context, - authentication, - { - user, - }, - ); + if (!accessResult.allowed) { + throw Error.forbidden( + "The user does not have access to the HASH instance, and therefore cannot complete account signup.", + ); + } - if (!onlyForEmails.some((email) => verifiedEmails.includes(email))) { - throw Error.forbidden( - "You must verify your email address before completing account setup.", - ); - } - } else if (!(await isUserEmailVerified(user.kratosIdentityId))) { + const onlyForEmails = accessResult.onlyForEmails ?? []; + + if (onlyForEmails.length > 0) { + const verifiedEmails = await getUserVerifiedEmails(context, authentication, { + user, + }); + + if (!onlyForEmails.some((email) => verifiedEmails.includes(email))) { throw Error.forbidden( "You must verify your email address before completing account setup.", ); } + } else if (!(await isUserEmailVerified(user.kratosIdentityId))) { + throw Error.forbidden("You must verify your email address before completing account setup."); + } - if (!updatedShortname || !updatedDisplayName) { - throw Error.badUserInput( - "You must set both shortname and display name to complete account signup.", - ); - } - - // Now that the user has completed signup, we can transfer the ownership of the web - // allowing them to create entities and types. - await addActorGroupAdministrator( - context.graphApi, - { actorId: systemAccountId }, - { actorId: user.accountId, actorGroupId: user.accountId }, - ); - - await updateWebShortname( - context.graphApi, - { actorId: systemAccountId }, - { webId: user.accountId as WebId, shortname: updatedShortname }, + if (!updatedShortname || !updatedDisplayName) { + throw Error.badUserInput( + "You must set both shortname and display name to complete account signup.", ); } - }; + + // Now that the user has completed signup, we can transfer the ownership of the web + // allowing them to create entities and types. + await addActorGroupAdministrator( + context.graphApi, + { actorId: systemAccountId }, + { actorId: user.accountId, actorGroupId: user.accountId }, + ); + + await updateWebShortname( + context.graphApi, + { actorId: systemAccountId }, + { webId: user.accountId as WebId, shortname: updatedShortname }, + ); + } +}; diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/create-entity-hooks.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/create-entity-hooks.ts index c76fe11acb1..5c03d80ce08 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/create-entity-hooks.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/create-entity-hooks.ts @@ -1,8 +1,5 @@ import type { ImpureGraphContext } from "../../../context-types"; -import type { - PropertyObjectWithMetadata, - VersionedUrl, -} from "@blockprotocol/type-system"; +import type { PropertyObjectWithMetadata, VersionedUrl } from "@blockprotocol/type-system"; import type { AuthenticationContext } from "@local/hash-graph-sdk/authentication-context"; import type { HashEntity } from "@local/hash-graph-sdk/entity"; diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/shared/mention-notification.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/shared/mention-notification.ts index 382c248669d..d681e9ff5e0 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/shared/mention-notification.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/shared/mention-notification.ts @@ -3,10 +3,7 @@ import { includesPageEntityTypeId } from "@local/hash-isomorphic-utils/page-enti import { getBlockCollectionByBlock } from "../../../system-types/block"; import { getCommentAncestorBlock } from "../../../system-types/comment"; import { getPageFromEntity } from "../../../system-types/page"; -import { - getCommentByText, - getPageAndBlockByText, -} from "../../../system-types/text"; +import { getCommentByText, getPageAndBlockByText } from "../../../system-types/text"; import type { ImpureGraphFunction } from "../../../../context-types"; import type { Block } from "../../../system-types/block"; @@ -22,37 +19,23 @@ export const getTextUpdateOccurredIn: ImpureGraphFunction< occurredInComment?: Comment; }> > = async (context, authentication, params) => { - const pageAndBlock = await getPageAndBlockByText( - context, - authentication, - params, - ); + const pageAndBlock = await getPageAndBlockByText(context, authentication, params); if (pageAndBlock) { const { page, block } = pageAndBlock; return { occurredInEntity: page, occurredInBlock: block }; } - const commentWithText = await getCommentByText( - context, - authentication, - params, - ); + const commentWithText = await getCommentByText(context, authentication, params); if (commentWithText) { - const commentAncestorBlock = await getCommentAncestorBlock( - context, - authentication, - { commentEntityId: commentWithText.entity.metadata.recordId.entityId }, - ); + const commentAncestorBlock = await getCommentAncestorBlock(context, authentication, { + commentEntityId: commentWithText.entity.metadata.recordId.entityId, + }); - const blockCollectionEntity = await getBlockCollectionByBlock( - context, - authentication, - { - block: commentAncestorBlock, - }, - ); + const blockCollectionEntity = await getBlockCollectionByBlock(context, authentication, { + block: commentAncestorBlock, + }); if ( blockCollectionEntity && diff --git a/apps/hash-api/src/graph/knowledge/primitive/entity/update-entity-hooks.ts b/apps/hash-api/src/graph/knowledge/primitive/entity/update-entity-hooks.ts index be19b312c07..5976df2c5c5 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/entity/update-entity-hooks.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/entity/update-entity-hooks.ts @@ -1,8 +1,5 @@ import type { ImpureGraphContext } from "../../../context-types"; -import type { - PropertyPatchOperation, - VersionedUrl, -} from "@blockprotocol/type-system"; +import type { PropertyPatchOperation, VersionedUrl } from "@blockprotocol/type-system"; import type { AuthenticationContext } from "@local/hash-graph-sdk/authentication-context"; import type { HashEntity } from "@local/hash-graph-sdk/entity"; diff --git a/apps/hash-api/src/graph/knowledge/primitive/link-entity.ts b/apps/hash-api/src/graph/knowledge/primitive/link-entity.ts index 9e40fa0f259..b7ab131391c 100644 --- a/apps/hash-api/src/graph/knowledge/primitive/link-entity.ts +++ b/apps/hash-api/src/graph/knowledge/primitive/link-entity.ts @@ -9,47 +9,34 @@ import type { PropertyPatchOperation, TypeIdsAndPropertiesForEntity, } from "@blockprotocol/type-system"; -import type { - CreateEntityParameters, - HashEntity, -} from "@local/hash-graph-sdk/entity"; +import type { CreateEntityParameters, HashEntity } from "@local/hash-graph-sdk/entity"; -export const isEntityLinkEntity = ( - entity: HashEntity, -): entity is HashLinkEntity => !!entity.linkData; +export const isEntityLinkEntity = (entity: HashEntity): entity is HashLinkEntity => + !!entity.linkData; -type CreateLinkEntityFunction< - Properties extends TypeIdsAndPropertiesForEntity, -> = ImpureGraphFunction< - Omit, "provenance"> & { - linkData: LinkData; - }, - Promise> ->; +type CreateLinkEntityFunction = + ImpureGraphFunction< + Omit, "provenance"> & { + linkData: LinkData; + }, + Promise> + >; /** * Create an entity. */ -export const createLinkEntity = async < - Properties extends TypeIdsAndPropertiesForEntity, ->( +export const createLinkEntity = async ( ...args: Parameters> ): ReturnType> => { const [context, authentication, params] = args; - const linkEntity = await HashLinkEntity.create( - context.graphApi, - authentication, - { - ...params, - provenance: context.provenance, - }, - ); + const linkEntity = await HashLinkEntity.create(context.graphApi, authentication, { + ...params, + provenance: context.provenance, + }); for (const afterCreateHook of afterCreateEntityHooks) { - if ( - linkEntity.metadata.entityTypeIds.includes(afterCreateHook.entityTypeId) - ) { + if (linkEntity.metadata.entityTypeIds.includes(afterCreateHook.entityTypeId)) { void afterCreateHook.callback({ context, entity: linkEntity, diff --git a/apps/hash-api/src/graph/knowledge/system-types/account.fields.ts b/apps/hash-api/src/graph/knowledge/system-types/account.fields.ts index 6276a76430e..f3d0fe08253 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/account.fields.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/account.fields.ts @@ -1,10 +1,7 @@ import { getOrgByShortname } from "./org"; import { getUser } from "./user"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; /** @todo: enable admins to expand upon restricted shortnames block list */ export const RESTRICTED_SHORTNAMES = [ @@ -104,10 +101,9 @@ export const shortnameContainsInvalidCharacter: PureGraphFunction< return !!shortname.search(ALLOWED_SHORTNAME_CHARS); }; -export const shortnameIsRestricted: PureGraphFunction< - { shortname: string }, - boolean -> = ({ shortname }): boolean => { +export const shortnameIsRestricted: PureGraphFunction<{ shortname: string }, boolean> = ({ + shortname, +}): boolean => { return RESTRICTED_SHORTNAMES.includes(shortname.toLowerCase()); }; @@ -130,10 +126,9 @@ export const shortnameIsTaken: ImpureGraphFunction< ); }; -export const shortnameIsInvalid: PureGraphFunction< - { shortname: string }, - boolean -> = (params): boolean => { +export const shortnameIsInvalid: PureGraphFunction<{ shortname: string }, boolean> = ( + params, +): boolean => { return ( params.shortname.length < shortnameMinimumLength || params.shortname.length > shortnameMaximumLength || diff --git a/apps/hash-api/src/graph/knowledge/system-types/block-collection.ts b/apps/hash-api/src/graph/knowledge/system-types/block-collection.ts index 2c587bff1f8..d62ca4a81aa 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/block-collection.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/block-collection.ts @@ -1,18 +1,12 @@ import { extractWebIdFromEntityId } from "@blockprotocol/type-system"; -import { - HashLinkEntity, - mergePropertyObjectAndMetadata, -} from "@local/hash-graph-sdk/entity"; +import { HashLinkEntity, mergePropertyObjectAndMetadata } from "@local/hash-graph-sdk/entity"; import { sortBlockCollectionLinks } from "@local/hash-isomorphic-utils/block-collection"; import { systemEntityTypes, systemLinkEntityTypes, } from "@local/hash-isomorphic-utils/ontology-type-ids"; -import { - getEntityOutgoingLinks, - getLatestEntityById, -} from "../primitive/entity"; +import { getEntityOutgoingLinks, getLatestEntityById } from "../primitive/entity"; import { createLinkEntity, getLinkEntityRightEntity, @@ -23,11 +17,7 @@ import { getBlockFromEntity } from "./block"; import type { PositionInput } from "../../../graphql/api-types.gen"; import type { ImpureGraphFunction } from "../../context-types"; import type { Block } from "./block"; -import type { - Entity, - EntityId, - VersionedUrl, -} from "@blockprotocol/type-system"; +import type { Entity, EntityId, VersionedUrl } from "@blockprotocol/type-system"; import type { HasSpatiallyPositionedContent } from "@local/hash-isomorphic-utils/system-types/canvas"; import type { HasIndexedContent } from "@local/hash-isomorphic-utils/system-types/shared"; @@ -43,43 +33,27 @@ export const getBlockCollectionBlocks: ImpureGraphFunction< }, Promise< { - linkEntity: HashLinkEntity< - HasSpatiallyPositionedContent | HasIndexedContent - >; + linkEntity: HashLinkEntity; rightEntity: Block; }[] > -> = async ( - ctx, - authentication, - { blockCollectionEntityId, blockCollectionEntityTypeIds }, -) => { - const isCanvas = blockCollectionEntityTypeIds.includes( - systemEntityTypes.canvas.entityTypeId, - ); +> = async (ctx, authentication, { blockCollectionEntityId, blockCollectionEntityTypeIds }) => { + const isCanvas = blockCollectionEntityTypeIds.includes(systemEntityTypes.canvas.entityTypeId); - const outgoingBlockDataLinks = (await getEntityOutgoingLinks( - ctx, - authentication, - { - entityId: blockCollectionEntityId, - linkEntityTypeVersionedUrl: isCanvas - ? systemLinkEntityTypes.hasSpatiallyPositionedContent.linkEntityTypeId - : systemLinkEntityTypes.hasIndexedContent.linkEntityTypeId, - }, - )) as - | HashLinkEntity[] - | HashLinkEntity[]; + const outgoingBlockDataLinks = (await getEntityOutgoingLinks(ctx, authentication, { + entityId: blockCollectionEntityId, + linkEntityTypeVersionedUrl: isCanvas + ? systemLinkEntityTypes.hasSpatiallyPositionedContent.linkEntityTypeId + : systemLinkEntityTypes.hasIndexedContent.linkEntityTypeId, + })) as HashLinkEntity[] | HashLinkEntity[]; return await Promise.all( - outgoingBlockDataLinks - .sort(sortBlockCollectionLinks) - .map(async (linkEntity) => ({ + outgoingBlockDataLinks.sort(sortBlockCollectionLinks).map(async (linkEntity) => ({ + linkEntity, + rightEntity: await getLinkEntityRightEntity(ctx, authentication, { linkEntity, - rightEntity: await getLinkEntityRightEntity(ctx, authentication, { - linkEntity, - }).then((entity) => getBlockFromEntity({ entity })), - })), + }).then((entity) => getBlockFromEntity({ entity })), + })), ); }; @@ -104,22 +78,25 @@ export const addBlockToBlockCollection: ImpureGraphFunction< position: { canvasPosition, indexPosition }, } = params; - const linkEntity = await createLinkEntity< - HasSpatiallyPositionedContent | HasIndexedContent - >(ctx, authentication, { - // assume that link to block is owned by the same account as the blockCollection - webId: extractWebIdFromEntityId(blockCollectionEntityId), - properties: mergePropertyObjectAndMetadata< - HasSpatiallyPositionedContent | HasIndexedContent - >(canvasPosition || indexPosition, undefined), - linkData: { - leftEntityId: blockCollectionEntityId, - rightEntityId: block.entity.metadata.recordId.entityId, + const linkEntity = await createLinkEntity( + ctx, + authentication, + { + // assume that link to block is owned by the same account as the blockCollection + webId: extractWebIdFromEntityId(blockCollectionEntityId), + properties: mergePropertyObjectAndMetadata( + canvasPosition || indexPosition, + undefined, + ), + linkData: { + leftEntityId: blockCollectionEntityId, + rightEntityId: block.entity.metadata.recordId.entityId, + }, + entityTypeIds: canvasPosition + ? [systemLinkEntityTypes.hasSpatiallyPositionedContent.linkEntityTypeId] + : [systemLinkEntityTypes.hasIndexedContent.linkEntityTypeId], }, - entityTypeIds: canvasPosition - ? [systemLinkEntityTypes.hasSpatiallyPositionedContent.linkEntityTypeId] - : [systemLinkEntityTypes.hasIndexedContent.linkEntityTypeId], - }); + ); return linkEntity; }; @@ -153,9 +130,7 @@ export const moveBlockInBlockCollection: ImpureGraphFunction< { op: "replace", path: [], - property: mergePropertyObjectAndMetadata( - indexPosition || canvasPosition, - ), + property: mergePropertyObjectAndMetadata(indexPosition || canvasPosition), }, ], linkEntity: new HashLinkEntity(linkEntity), diff --git a/apps/hash-api/src/graph/knowledge/system-types/block.ts b/apps/hash-api/src/graph/knowledge/system-types/block.ts index 84f7c59521e..f366d875b26 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/block.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/block.ts @@ -33,10 +33,7 @@ import { } from "../primitive/link-entity"; import { getCommentFromEntity } from "./comment"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { Comment } from "./comment"; import type { Entity, EntityId } from "@blockprotocol/type-system"; import type { @@ -49,14 +46,8 @@ export type Block = { entity: HashEntity; }; -function assertBlockEntity( - entity: HashEntity, -): asserts entity is HashEntity { - if ( - !entity.metadata.entityTypeIds.includes( - systemEntityTypes.block.entityTypeId, - ) - ) { +function assertBlockEntity(entity: HashEntity): asserts entity is HashEntity { + if (!entity.metadata.entityTypeIds.includes(systemEntityTypes.block.entityTypeId)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, systemEntityTypes.block.entityTypeId, @@ -65,10 +56,9 @@ function assertBlockEntity( } } -export const getBlockFromEntity: PureGraphFunction< - { entity: HashEntity }, - Block -> = ({ entity }) => { +export const getBlockFromEntity: PureGraphFunction<{ entity: HashEntity }, Block> = ({ + entity, +}) => { assertBlockEntity(entity); const { componentId } = simplifyProperties(entity.properties); @@ -84,10 +74,11 @@ export const getBlockFromEntity: PureGraphFunction< * * @param params.entityId - the entity id of the block */ -export const getBlockById: ImpureGraphFunction< - { entityId: EntityId }, - Promise -> = async (ctx, authentication, { entityId }) => { +export const getBlockById: ImpureGraphFunction<{ entityId: EntityId }, Promise> = async ( + ctx, + authentication, + { entityId }, +) => { const entity = await getLatestEntityById(ctx, authentication, { entityId }); return getBlockFromEntity({ entity }); @@ -117,8 +108,7 @@ export const createBlock: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/component-id/": { value: componentId, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, }, @@ -144,19 +134,15 @@ export const createBlock: ImpureGraphFunction< * * @param params.block - the block */ -export const getBlockData: ImpureGraphFunction< - { block: Block }, - Promise -> = async (ctx, authentication, { block }) => { - const outgoingBlockDataLinks = await getEntityOutgoingLinks( - ctx, - authentication, - { - entityId: block.entity.metadata.recordId.entityId, - linkEntityTypeVersionedUrl: - systemLinkEntityTypes.hasData.linkEntityTypeId, - }, - ); +export const getBlockData: ImpureGraphFunction<{ block: Block }, Promise> = async ( + ctx, + authentication, + { block }, +) => { + const outgoingBlockDataLinks = await getEntityOutgoingLinks(ctx, authentication, { + entityId: block.entity.metadata.recordId.entityId, + linkEntityTypeVersionedUrl: systemLinkEntityTypes.hasData.linkEntityTypeId, + }); const outgoingBlockDataLink = outgoingBlockDataLinks[0]; @@ -186,15 +172,10 @@ export const updateBlockDataEntity: ImpureGraphFunction< Promise > = async (ctx, authentication, params) => { const { block, newBlockDataEntity } = params; - const outgoingBlockDataLinks = await getEntityOutgoingLinks( - ctx, - authentication, - { - entityId: block.entity.metadata.recordId.entityId, - linkEntityTypeVersionedUrl: - systemLinkEntityTypes.hasData.linkEntityTypeId, - }, - ); + const outgoingBlockDataLinks = await getEntityOutgoingLinks(ctx, authentication, { + entityId: block.entity.metadata.recordId.entityId, + linkEntityTypeVersionedUrl: systemLinkEntityTypes.hasData.linkEntityTypeId, + }); const outgoingBlockDataLink = outgoingBlockDataLinks[0]; @@ -204,13 +185,9 @@ export const updateBlockDataEntity: ImpureGraphFunction< ); } - const existingBlockDataEntity = await getLinkEntityRightEntity( - ctx, - authentication, - { - linkEntity: outgoingBlockDataLink, - }, - ); + const existingBlockDataEntity = await getLinkEntityRightEntity(ctx, authentication, { + linkEntity: outgoingBlockDataLink, + }); if ( existingBlockDataEntity.metadata.recordId.entityId === @@ -221,11 +198,7 @@ export const updateBlockDataEntity: ImpureGraphFunction< ); } - await outgoingBlockDataLink.archive( - ctx.graphApi, - authentication, - ctx.provenance, - ); + await outgoingBlockDataLink.archive(ctx.graphApi, authentication, ctx.provenance); await createLinkEntity(ctx, authentication, { webId: extractWebIdFromEntityId(block.entity.metadata.recordId.entityId), @@ -243,10 +216,11 @@ export const updateBlockDataEntity: ImpureGraphFunction< * * @param params.block - the block */ -export const getBlockComments: ImpureGraphFunction< - { block: Block }, - Promise -> = async (ctx, authentication, { block }) => { +export const getBlockComments: ImpureGraphFunction<{ block: Block }, Promise> = async ( + ctx, + authentication, + { block }, +) => { const blockCommentLinks = await getEntityIncomingLinks(ctx, authentication, { entityId: block.entity.metadata.recordId.entityId, linkEntityTypeId: systemLinkEntityTypes.hasParent.linkEntityTypeId, @@ -273,24 +247,19 @@ export const getBlockCollectionByBlock: ImpureGraphFunction< > = async (context, authentication, params) => { const { block, includeDrafts = false } = params; - const blockEntityUuid = extractEntityUuidFromEntityId( - block.entity.metadata.recordId.entityId, - ); + const blockEntityUuid = extractEntityUuidFromEntityId(block.entity.metadata.recordId.entityId); const matchingContainsLinks = await queryEntities(context, authentication, { filter: { all: [ contentLinkTypeFilter, { - equal: [ - { path: ["rightEntity", "uuid"] }, - { parameter: blockEntityUuid }, - ], + equal: [{ path: ["rightEntity", "uuid"] }, { parameter: blockEntityUuid }], }, - generateVersionedUrlMatchingFilter( - systemEntityTypes.blockCollection.entityTypeId, - { ignoreParents: false, pathPrefix: ["leftEntity"] }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.blockCollection.entityTypeId, { + ignoreParents: false, + pathPrefix: ["leftEntity"], + }), ], }, temporalAxes: currentTimeInstantTemporalAxes, @@ -303,13 +272,9 @@ export const getBlockCollectionByBlock: ImpureGraphFunction< const [matchingContainsLink] = matchingContainsLinks; if (matchingContainsLink) { - const blockCollectionEntity = await getLatestEntityById( - context, - authentication, - { - entityId: matchingContainsLink.linkData.leftEntityId, - }, - ); + const blockCollectionEntity = await getLatestEntityById(context, authentication, { + entityId: matchingContainsLink.linkData.leftEntityId, + }); return blockCollectionEntity; } diff --git a/apps/hash-api/src/graph/knowledge/system-types/comment.ts b/apps/hash-api/src/graph/knowledge/system-types/comment.ts index c1cfcc97464..8ca3fa215d9 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/comment.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/comment.ts @@ -14,26 +14,17 @@ import { getLatestEntityById, updateEntity, } from "../primitive/entity"; -import { - getLinkEntityLeftEntity, - getLinkEntityRightEntity, -} from "../primitive/link-entity"; +import { getLinkEntityLeftEntity, getLinkEntityRightEntity } from "../primitive/link-entity"; import { getBlockFromEntity } from "./block"; import { getTextFromEntity } from "./text"; import { getUserFromEntity } from "./user"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { Block } from "./block"; import type { Text } from "./text"; import type { User } from "./user"; import type { EntityId, EntityUuid } from "@blockprotocol/type-system"; -import type { - CreateEntityParameters, - HashEntity, -} from "@local/hash-graph-sdk/entity"; +import type { CreateEntityParameters, HashEntity } from "@local/hash-graph-sdk/entity"; import type { Comment as CommentEntity, CommentPropertiesWithMetadata, @@ -53,14 +44,8 @@ export type Comment = { entity: HashEntity; }; -function assertCommentEntity( - entity: HashEntity, -): asserts entity is HashEntity { - if ( - !entity.metadata.entityTypeIds.includes( - systemEntityTypes.comment.entityTypeId, - ) - ) { +function assertCommentEntity(entity: HashEntity): asserts entity is HashEntity { + if (!entity.metadata.entityTypeIds.includes(systemEntityTypes.comment.entityTypeId)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, systemEntityTypes.comment.entityTypeId, @@ -69,17 +54,14 @@ function assertCommentEntity( } } -export const getCommentFromEntity: PureGraphFunction< - { entity: HashEntity }, - Comment -> = ({ entity }) => { +export const getCommentFromEntity: PureGraphFunction<{ entity: HashEntity }, Comment> = ({ + entity, +}) => { assertCommentEntity(entity); return { - resolvedAt: - entity.properties["https://hash.ai/@h/types/property-type/resolved-at/"], - deletedAt: - entity.properties["https://hash.ai/@h/types/property-type/deleted-at/"], + resolvedAt: entity.properties["https://hash.ai/@h/types/property-type/resolved-at/"], + deletedAt: entity.properties["https://hash.ai/@h/types/property-type/deleted-at/"], entity, }; }; @@ -89,10 +71,11 @@ export const getCommentFromEntity: PureGraphFunction< * * @param params.entityId - the entity id of the comment */ -export const getCommentById: ImpureGraphFunction< - { entityId: EntityId }, - Promise -> = async (ctx, authentication, { entityId }) => { +export const getCommentById: ImpureGraphFunction<{ entityId: EntityId }, Promise> = async ( + ctx, + authentication, + { entityId }, +) => { const entity = await getLatestEntityById(ctx, authentication, { entityId }); return getCommentFromEntity({ entity }); @@ -160,16 +143,14 @@ export const createComment: ImpureGraphFunction< entityUuid: textEntityEntityUuid, properties: { value: { - "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/": - { - value: textualContent.map((text) => ({ - value: text, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", - }, - })), - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/": { + value: textualContent.map((text) => ({ + value: text, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + }, + })), + }, }, }, entityTypeIds: [systemEntityTypes.text.entityTypeId], @@ -259,8 +240,7 @@ export const updateCommentText: ImpureGraphFunction< value: textualContent.map((textToken) => ({ value: textToken, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", }, })), } satisfies TextPropertiesWithMetadata["value"]["https://blockprotocol.org/@blockprotocol/types/property-type/textual-content/"], @@ -315,8 +295,7 @@ export const getCommentParent: ImpureGraphFunction< > = async (ctx, authentication, { commentEntityId }) => { const parentLinks = await getEntityOutgoingLinks(ctx, authentication, { entityId: commentEntityId, - linkEntityTypeVersionedUrl: - systemLinkEntityTypes.hasParent.linkEntityTypeId, + linkEntityTypeVersionedUrl: systemLinkEntityTypes.hasParent.linkEntityTypeId, }); const [parentLink, ...unexpectedParentLinks] = parentLinks; @@ -349,8 +328,7 @@ export const getCommentAuthor: ImpureGraphFunction< > = async (ctx, authentication, { commentEntityId }) => { const authorLinks = await getEntityOutgoingLinks(ctx, authentication, { entityId: commentEntityId, - linkEntityTypeVersionedUrl: - systemLinkEntityTypes.authoredBy.linkEntityTypeId, + linkEntityTypeVersionedUrl: systemLinkEntityTypes.authoredBy.linkEntityTypeId, }); const [authorLink, ...unexpectedAuthorLinks] = authorLinks; @@ -391,12 +369,8 @@ export const getCommentReplies: ImpureGraphFunction< }); return Promise.all( - replyLinks.map((linkEntity) => - getLinkEntityLeftEntity(ctx, authentication, { linkEntity }), - ), - ).then((entities) => - entities.map((entity) => getCommentFromEntity({ entity })), - ); + replyLinks.map((linkEntity) => getLinkEntityLeftEntity(ctx, authentication, { linkEntity })), + ).then((entities) => entities.map((entity) => getCommentFromEntity({ entity }))); }; /** @@ -447,11 +421,7 @@ export const getCommentAncestorBlock: ImpureGraphFunction< commentEntityId, }); - if ( - parentEntity.metadata.entityTypeIds.includes( - systemEntityTypes.block.entityTypeId, - ) - ) { + if (parentEntity.metadata.entityTypeIds.includes(systemEntityTypes.block.entityTypeId)) { // @todo - make sure the entity is really a block return getBlockFromEntity({ entity: parentEntity as Block["entity"] }); } else { diff --git a/apps/hash-api/src/graph/knowledge/system-types/file.ts b/apps/hash-api/src/graph/knowledge/system-types/file.ts index 944d95b7c26..e70de495359 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/file.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/file.ts @@ -2,35 +2,20 @@ import mime from "mime-types"; import { extractWebIdFromEntityId } from "@blockprotocol/type-system"; import { typedEntries } from "@local/advanced-types/typed-entries"; -import { - formatFileUrl, - getEntityTypeIdForMimeType, -} from "@local/hash-backend-utils/file-storage"; +import { formatFileUrl, getEntityTypeIdForMimeType } from "@local/hash-backend-utils/file-storage"; import { validateExternalUrl } from "@local/hash-backend-utils/url-validation"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; import { normalizeWhitespace } from "@local/hash-isomorphic-utils/normalize"; import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; -import { - createEntity, - getLatestEntityById, - updateEntity, -} from "../primitive/entity"; +import { createEntity, getLatestEntityById, updateEntity } from "../primitive/entity"; import type { MutationCreateFileFromUrlArgs, MutationRequestFileUploadArgs, } from "../../../graphql/api-types.gen"; -import type { - ImpureGraphContext, - ImpureGraphFunction, -} from "../../context-types"; -import type { - BaseUrl, - Entity, - VersionedUrl, - WebId, -} from "@blockprotocol/type-system"; +import type { ImpureGraphContext, ImpureGraphFunction } from "../../context-types"; +import type { BaseUrl, Entity, VersionedUrl, WebId } from "@blockprotocol/type-system"; import type { PresignedPutUpload } from "@local/hash-backend-utils/file-storage"; import type { AuthenticationContext } from "@local/hash-graph-sdk/authentication-context"; import type { HashEntity } from "@local/hash-graph-sdk/entity"; @@ -63,13 +48,9 @@ const generateCommonParameters = async ( } if (fileEntityUpdateInput) { - const existingEntity = await getLatestEntityById( - ctx, - authentication, - { - entityId: fileEntityUpdateInput.existingFileEntityId, - }, - ); + const existingEntity = await getLatestEntityById(ctx, authentication, { + entityId: fileEntityUpdateInput.existingFileEntityId, + }); return { existingEntity, @@ -77,9 +58,7 @@ const generateCommonParameters = async ( ? [fileEntityUpdateInput.entityTypeId] : existingEntity.metadata.entityTypeIds, mimeType, - webId: extractWebIdFromEntityId( - existingEntity.metadata.recordId.entityId, - ), + webId: extractWebIdFromEntityId(existingEntity.metadata.recordId.entityId), }; } else if (fileEntityCreationInput) { const { entityTypeId: specifiedEntityTypeId } = fileEntityCreationInput; @@ -89,9 +68,7 @@ const generateCommonParameters = async ( let entityTypeId: VersionedUrl; if (specifiedEntityTypeId) { - const isHashEntityType = specifiedEntityTypeId.startsWith( - "https://hash.ai/@h/", - ); + const isHashEntityType = specifiedEntityTypeId.startsWith("https://hash.ai/@h/"); if (isHashEntityType) { /** @@ -105,8 +82,7 @@ const generateCommonParameters = async ( * the specified type ID */ entityTypeId = - entityTypeIdByMimeType && - specifiedEntityTypeId !== entityTypeIdByMimeType + entityTypeIdByMimeType && specifiedEntityTypeId !== entityTypeIdByMimeType ? entityTypeIdByMimeType : specifiedEntityTypeId; } else { @@ -121,8 +97,7 @@ const generateCommonParameters = async ( * If no entity type ID was specified, we use the mime entity type ID * directly if it exists, otherwise we use the default `File` entity. */ - entityTypeId = - entityTypeIdByMimeType ?? systemEntityTypes.file.entityTypeId; + entityTypeId = entityTypeIdByMimeType ?? systemEntityTypes.file.entityTypeId; } return { @@ -133,9 +108,7 @@ const generateCommonParameters = async ( }; } - throw new Error( - "One of fileEntityCreationInput or fileEntityUpdateInput must be provided", - ); + throw new Error("One of fileEntityCreationInput or fileEntityUpdateInput must be provided"); }; export const createFileFromUploadRequest: ImpureGraphFunction< @@ -157,8 +130,12 @@ export const createFileFromUploadRequest: ImpureGraphFunction< const name = normalizeWhitespace(unnormalizedFilename); - const { entityTypeIds, existingEntity, mimeType, webId } = - await generateCommonParameters(ctx, authentication, params, name); + const { entityTypeIds, existingEntity, mimeType, webId } = await generateCommonParameters( + ctx, + authentication, + params, + name, + ); const displayName = providedDisplayName ?? name; @@ -166,70 +143,56 @@ export const createFileFromUploadRequest: ImpureGraphFunction< value: { ...(description !== undefined && description !== null ? { - "https://blockprotocol.org/@blockprotocol/types/property-type/description/": - { - value: description, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/description/": { + value: description, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, + }, } : {}), - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": - { - value: "https://placehold.co/600x400?text=PLACEHOLDER", - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": { + value: "https://placehold.co/600x400?text=PLACEHOLDER", + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": - { - value: name, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": { + value: name, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": - { - value: displayName, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": { + value: displayName, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": - { - value: mimeType, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": { + value: mimeType, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/": - { - value: name, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/": { + value: name, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/": - { - value: "Upload", - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/": { + value: "Upload", + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/": - { - value: size, - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/bytes/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-size/": { + value: size, + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/bytes/v/1", }, + }, }, }; @@ -251,40 +214,36 @@ export const createFileFromUploadRequest: ImpureGraphFunction< }); try { - const { fileStorageProperties, presignedPut } = - await uploadProvider.presignUpload({ - key, - headers: { - "content-length": size, - "content-type": mimeType, - }, - expiresInSeconds: UPLOAD_URL_EXPIRATION_SECONDS, - }); + const { fileStorageProperties, presignedPut } = await uploadProvider.presignUpload({ + key, + headers: { + "content-length": size, + "content-type": mimeType, + }, + expiresInSeconds: UPLOAD_URL_EXPIRATION_SECONDS, + }); const updatedProperties: File["propertiesWithMetadata"] = { ...fileStorageProperties, value: { ...fileStorageProperties.value, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": - { - value: formatFileUrl(key), - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": { + value: formatFileUrl(key), + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", }, + }, }, }; const entity = await updateEntity(ctx, authentication, { entity: fileEntity, entityTypeIds, - propertyPatches: typedEntries(updatedProperties.value).map( - ([baseUrl, property]) => ({ - op: "add", - path: [baseUrl as BaseUrl], - property, - }), - ), + propertyPatches: typedEntries(updatedProperties.value).map(([baseUrl, property]) => ({ + op: "add", + path: [baseUrl as BaseUrl], + property, + })), }); return { @@ -306,15 +265,17 @@ export const createFileFromExternalUrl: ImpureGraphFunction< const urlValidation = validateExternalUrl(url); if (!urlValidation.valid) { - throw new Error( - `The provided URL is not permitted: ${urlValidation.reason}`, - ); + throw new Error(`The provided URL is not permitted: ${urlValidation.reason}`); } const filename = normalizeWhitespace(url.split("/").pop()!); - const { entityTypeIds, existingEntity, mimeType, webId } = - await generateCommonParameters(ctx, authentication, params, filename); + const { entityTypeIds, existingEntity, mimeType, webId } = await generateCommonParameters( + ctx, + authentication, + params, + filename, + ); const displayName = providedDisplayName ?? filename; @@ -323,70 +284,56 @@ export const createFileFromExternalUrl: ImpureGraphFunction< value: { ...(description !== undefined && description !== null ? { - "https://blockprotocol.org/@blockprotocol/types/property-type/description/": - { - value: description, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/description/": { + value: description, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, + }, } : {}), - "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": - { - value: filename, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-name/": { + value: filename, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": - { - value: displayName, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": { + value: displayName, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": - { - value: url, - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/file-url/": { + value: url, + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": - { - value: mimeType, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/": { + value: mimeType, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/": - { - value: filename, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/original-file-name/": { + value: filename, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/": - { - value: "URL", - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/original-source/": { + value: "URL", + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, - "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/": - { - value: url, - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", - }, + }, + "https://blockprotocol.org/@blockprotocol/types/property-type/original-url/": { + value: url, + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", }, + }, }, }; @@ -395,10 +342,7 @@ export const createFileFromExternalUrl: ImpureGraphFunction< entity: existingEntity, entityTypeIds, propertyPatches: typedEntries(properties.value) - .filter( - ([baseUrl, property]) => - existingEntity.properties[baseUrl] !== property.value, - ) + .filter(([baseUrl, property]) => existingEntity.properties[baseUrl] !== property.value) .map(([baseUrl, property]) => ({ op: existingEntity.properties[baseUrl] ? "replace" : "add", path: [baseUrl as BaseUrl], @@ -411,8 +355,6 @@ export const createFileFromExternalUrl: ImpureGraphFunction< entityTypeIds: entityTypeIds as File["entityTypeIds"], }); } catch (error) { - throw new Error( - `There was an error creating the file entity from a link: ${error}`, - ); + throw new Error(`There was an error creating the file entity from a link: ${error}`); } }; diff --git a/apps/hash-api/src/graph/knowledge/system-types/flow-schedule.ts b/apps/hash-api/src/graph/knowledge/system-types/flow-schedule.ts index 678d15af3b4..350056b2f65 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/flow-schedule.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/flow-schedule.ts @@ -10,11 +10,7 @@ import { systemPropertyTypes, } from "@local/hash-isomorphic-utils/ontology-type-ids"; -import { - createEntity, - getLatestEntityById, - updateEntity, -} from "../primitive/entity"; +import { createEntity, getLatestEntityById, updateEntity } from "../primitive/entity"; import type { ImpureGraphFunction } from "../../context-types"; import type { EntityId } from "@blockprotocol/type-system"; @@ -30,12 +26,8 @@ import type { ScheduleStatusPropertyValueWithMetadata, } from "@local/hash-isomorphic-utils/system-types/shared"; -const isEntityFlowScheduleEntity = ( - entity: HashEntity, -): entity is HashEntity => - entity.metadata.entityTypeIds.includes( - systemEntityTypes.flowSchedule.entityTypeId, - ); +const isEntityFlowScheduleEntity = (entity: HashEntity): entity is HashEntity => + entity.metadata.entityTypeIds.includes(systemEntityTypes.flowSchedule.entityTypeId); export const createFlowSchedule: ImpureGraphFunction< CreateFlowScheduleInput, @@ -60,15 +52,13 @@ export const createFlowSchedule: ImpureGraphFunction< "https://blockprotocol.org/@blockprotocol/types/property-type/name/": { value: name, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/flow-definition-id/": { value: flowDefinitionId, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/flow-type/": { @@ -80,15 +70,13 @@ export const createFlowSchedule: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/schedule-spec/": { value: scheduleSpec, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", }, }, "https://hash.ai/@h/types/property-type/schedule-overlap-policy/": { value: overlapPolicy, metadata: { - dataTypeId: - "https://hash.ai/@h/types/data-type/schedule-overlap-policy/v/1", + dataTypeId: "https://hash.ai/@h/types/data-type/schedule-overlap-policy/v/1", }, }, "https://hash.ai/@h/types/property-type/schedule-status/": { @@ -102,8 +90,7 @@ export const createFlowSchedule: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/trigger-definition-id/": { value: flowTrigger.triggerDefinitionId, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, ...(flowTrigger.outputs @@ -130,8 +117,7 @@ export const createFlowSchedule: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/pause-on-failure/": { value: pauseOnFailure, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", }, }, ...(dataSources @@ -139,8 +125,7 @@ export const createFlowSchedule: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/data-sources/": { value: dataSources, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", }, }, } @@ -188,8 +173,7 @@ export const updateFlowSchedule: ImpureGraphFunction< scheduleEntityId, }); - const propertyPatches: Parameters[2]["propertyPatches"] = - []; + const propertyPatches: Parameters[2]["propertyPatches"] = []; if (updates.name !== undefined) { propertyPatches.push({ @@ -198,8 +182,7 @@ export const updateFlowSchedule: ImpureGraphFunction< property: { value: updates.name, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, }); @@ -212,8 +195,7 @@ export const updateFlowSchedule: ImpureGraphFunction< property: { value: updates.scheduleSpec, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", }, }, }); @@ -226,8 +208,7 @@ export const updateFlowSchedule: ImpureGraphFunction< property: { value: updates.overlapPolicy, metadata: { - dataTypeId: - "https://hash.ai/@h/types/data-type/schedule-overlap-policy/v/1", + dataTypeId: "https://hash.ai/@h/types/data-type/schedule-overlap-policy/v/1", }, }, }); @@ -253,8 +234,7 @@ export const updateFlowSchedule: ImpureGraphFunction< property: { value: updates.pauseOnFailure, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", }, }, }); @@ -267,8 +247,7 @@ export const updateFlowSchedule: ImpureGraphFunction< property: { value: updates.dataSources, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", }, }, }); @@ -278,14 +257,10 @@ export const updateFlowSchedule: ImpureGraphFunction< return existingEntity; } - const updatedEntity = await updateEntity( - context, - authentication, - { - entity: existingEntity, - propertyPatches, - }, - ); + const updatedEntity = await updateEntity(context, authentication, { + entity: existingEntity, + propertyPatches, + }); return updatedEntity; }; @@ -296,51 +271,46 @@ export const pauseFlowSchedule: ImpureGraphFunction< false, true > = async (context, authentication, { existingEntity, note }) => { - const updatedEntity = await updateEntity( - context, - authentication, - { - entity: existingEntity, - propertyPatches: [ - { - op: "replace", - path: [systemPropertyTypes.scheduleStatus.propertyTypeBaseUrl], - property: { - value: "paused", - metadata: { - dataTypeId: - "https://hash.ai/@h/types/data-type/schedule-status/v/1", - }, - } satisfies ScheduleStatusPropertyValueWithMetadata, - }, - { - op: "add", - path: [systemPropertyTypes.schedulePauseState.propertyTypeBaseUrl], - property: { - value: { - "https://hash.ai/@h/types/property-type/paused-at/": { - value: new Date().toISOString(), - metadata: { - dataTypeId: "https://hash.ai/@h/types/data-type/datetime/v/1", - }, + const updatedEntity = await updateEntity(context, authentication, { + entity: existingEntity, + propertyPatches: [ + { + op: "replace", + path: [systemPropertyTypes.scheduleStatus.propertyTypeBaseUrl], + property: { + value: "paused", + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/schedule-status/v/1", + }, + } satisfies ScheduleStatusPropertyValueWithMetadata, + }, + { + op: "add", + path: [systemPropertyTypes.schedulePauseState.propertyTypeBaseUrl], + property: { + value: { + "https://hash.ai/@h/types/property-type/paused-at/": { + value: new Date().toISOString(), + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/datetime/v/1", }, - ...(note - ? { - "https://hash.ai/@h/types/property-type/explanation/": { - value: note, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, - }, - } - : {}), }, - } satisfies SchedulePauseStatePropertyValueWithMetadata, - }, - ], - }, - ); + ...(note + ? { + "https://hash.ai/@h/types/property-type/explanation/": { + value: note, + metadata: { + dataTypeId: + "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + }, + }, + } + : {}), + }, + } satisfies SchedulePauseStatePropertyValueWithMetadata, + }, + ], + }); return updatedEntity; }; @@ -353,25 +323,19 @@ export const resumeFlowSchedule: ImpureGraphFunction< Promise>, false, true -> = async ( - context, - authentication, - { existingEntity, hasSchedulePauseState }, -) => { - const propertyPatches: Parameters[2]["propertyPatches"] = - [ - { - op: "replace", - path: [systemPropertyTypes.scheduleStatus.propertyTypeBaseUrl], - property: { - value: "active", - metadata: { - dataTypeId: - "https://hash.ai/@h/types/data-type/schedule-status/v/1", - }, +> = async (context, authentication, { existingEntity, hasSchedulePauseState }) => { + const propertyPatches: Parameters[2]["propertyPatches"] = [ + { + op: "replace", + path: [systemPropertyTypes.scheduleStatus.propertyTypeBaseUrl], + property: { + value: "active", + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/schedule-status/v/1", }, }, - ]; + }, + ]; if (hasSchedulePauseState) { propertyPatches.push({ @@ -380,14 +344,10 @@ export const resumeFlowSchedule: ImpureGraphFunction< }); } - const updatedEntity = await updateEntity( - context, - authentication, - { - entity: existingEntity, - propertyPatches, - }, - ); + const updatedEntity = await updateEntity(context, authentication, { + entity: existingEntity, + propertyPatches, + }); return updatedEntity; }; @@ -411,8 +371,7 @@ export const revertFlowSchedulePause: ImpureGraphFunction< property: { value: "active", metadata: { - dataTypeId: - "https://hash.ai/@h/types/data-type/schedule-status/v/1", + dataTypeId: "https://hash.ai/@h/types/data-type/schedule-status/v/1", }, }, }, @@ -437,20 +396,18 @@ export const revertFlowScheduleResume: ImpureGraphFunction< false, true > = async (context, authentication, { resumedEntity, previousPauseState }) => { - const propertyPatches: Parameters[2]["propertyPatches"] = - [ - { - op: "replace", - path: [systemPropertyTypes.scheduleStatus.propertyTypeBaseUrl], - property: { - value: "paused", - metadata: { - dataTypeId: - "https://hash.ai/@h/types/data-type/schedule-status/v/1", - }, - } satisfies ScheduleStatusPropertyValueWithMetadata, - }, - ]; + const propertyPatches: Parameters[2]["propertyPatches"] = [ + { + op: "replace", + path: [systemPropertyTypes.scheduleStatus.propertyTypeBaseUrl], + property: { + value: "paused", + metadata: { + dataTypeId: "https://hash.ai/@h/types/data-type/schedule-status/v/1", + }, + } satisfies ScheduleStatusPropertyValueWithMetadata, + }, + ]; // Only restore schedulePauseState if it existed before if (previousPauseState !== undefined) { @@ -460,8 +417,7 @@ export const revertFlowScheduleResume: ImpureGraphFunction< property: { value: previousPauseState, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/object/v/1", }, }, }); diff --git a/apps/hash-api/src/graph/knowledge/system-types/hash-instance.ts b/apps/hash-api/src/graph/knowledge/system-types/hash-instance.ts index 12e0208558b..e9fcb7c8926 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/hash-instance.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/hash-instance.ts @@ -33,27 +33,20 @@ export const createHashInstance: ImpureGraphFunction< Promise > = async (ctx, authentication, params) => { // Ensure the hash instance entity has not already been created. - const existingHashInstance = await getHashInstance(ctx, authentication).catch( - (error: Error) => { - if (error instanceof NotFoundError) { - return null; - } - throw error; - }, - ); + const existingHashInstance = await getHashInstance(ctx, authentication).catch((error: Error) => { + if (error instanceof NotFoundError) { + return null; + } + throw error; + }); if (existingHashInstance) { throw new Error("HASH instance entity already exists."); } - const { id: teamId, webId } = await getInstanceAdminsTeam( - ctx, - authentication, - ); + const { id: teamId, webId } = await getInstanceAdminsTeam(ctx, authentication); - logger.info( - `Retrieved account group for hash instance admins with id: ${teamId}`, - ); + logger.info(`Retrieved account group for hash instance admins with id: ${teamId}`); const instantiationPolicy = await createPolicy(ctx.graphApi, authentication, { name: "tmp-hash-instance-instantiate", @@ -80,39 +73,30 @@ export const createHashInstance: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/pages-are-enabled/": { value: params.pagesAreEnabled ?? true, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", }, }, - "https://hash.ai/@h/types/property-type/user-self-registration-is-enabled/": - { - value: params.userSelfRegistrationIsEnabled ?? true, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", - }, + "https://hash.ai/@h/types/property-type/user-self-registration-is-enabled/": { + value: params.userSelfRegistrationIsEnabled ?? true, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", }, - "https://hash.ai/@h/types/property-type/user-registration-by-invitation-is-enabled/": - { - value: params.userRegistrationByInviteIsEnabled ?? true, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", - }, + }, + "https://hash.ai/@h/types/property-type/user-registration-by-invitation-is-enabled/": { + value: params.userRegistrationByInviteIsEnabled ?? true, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", }, - "https://hash.ai/@h/types/property-type/org-self-registration-is-enabled/": - { - value: params.orgSelfRegistrationIsEnabled ?? true, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", - }, + }, + "https://hash.ai/@h/types/property-type/org-self-registration-is-enabled/": { + value: params.orgSelfRegistrationIsEnabled ?? true, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", }, + }, }, }, - entityTypeIds: [ - params.hashInstanceEntityTypeId, - ] as HashInstanceEntity["entityTypeIds"], + entityTypeIds: [params.hashInstanceEntityTypeId] as HashInstanceEntity["entityTypeIds"], }); return getHashInstanceFromEntity({ entity }); diff --git a/apps/hash-api/src/graph/knowledge/system-types/linear-integration-entity.ts b/apps/hash-api/src/graph/knowledge/system-types/linear-integration-entity.ts index 70818ab2ddb..b94949ed9b8 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/linear-integration-entity.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/linear-integration-entity.ts @@ -1,17 +1,10 @@ -import { - getRightEntityForLinkEntity, - getRoots, -} from "@blockprotocol/graph/stdlib"; +import { getRightEntityForLinkEntity, getRoots } from "@blockprotocol/graph/stdlib"; import { extractEntityUuidFromEntityId, extractWebIdFromEntityId, } from "@blockprotocol/type-system"; import { EntityTypeMismatchError } from "@local/hash-backend-utils/error"; -import { - type HashEntity, - queryEntities, - queryEntitySubgraph, -} from "@local/hash-graph-sdk/entity"; +import { type HashEntity, queryEntities, queryEntitySubgraph } from "@local/hash-graph-sdk/entity"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; import { currentTimeInstantTemporalAxes, @@ -27,10 +20,7 @@ import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-proper import { getLatestEntityById, updateEntity } from "../primitive/entity"; import { createLinkEntity } from "../primitive/link-entity"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { ActorEntityUuid, BaseUrl, @@ -52,11 +42,7 @@ export type LinearIntegration = { function assertLinearIntegrationEntity( entity: Entity, ): asserts entity is Entity { - if ( - !entity.metadata.entityTypeIds.includes( - systemEntityTypes.linearIntegration.entityTypeId, - ) - ) { + if (!entity.metadata.entityTypeIds.includes(systemEntityTypes.linearIntegration.entityTypeId)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, systemEntityTypes.linearIntegration.entityTypeId, @@ -85,34 +71,26 @@ export const getAllLinearIntegrationsWithLinearOrgId: ImpureGraphFunction< > = async (context, authentication, params) => { const { linearOrgId, includeDrafts = false } = params; - const { entities } = await queryEntities( - context, - authentication, - { - filter: { - all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.linearIntegration.entityTypeId, - { ignoreParents: true }, - ), - { - equal: [ - { - path: [ - "properties", - systemPropertyTypes.linearOrgId.propertyTypeBaseUrl, - ], - }, - { parameter: linearOrgId }, - ], - }, - ], - }, - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts, - includePermissions: false, + const { entities } = await queryEntities(context, authentication, { + filter: { + all: [ + generateVersionedUrlMatchingFilter(systemEntityTypes.linearIntegration.entityTypeId, { + ignoreParents: true, + }), + { + equal: [ + { + path: ["properties", systemPropertyTypes.linearOrgId.propertyTypeBaseUrl], + }, + { parameter: linearOrgId }, + ], + }, + ], }, - ); + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts, + includePermissions: false, + }); return entities.map((entity) => getLinearIntegrationFromEntity({ entity })); }; @@ -135,17 +113,13 @@ export const getLinearIntegrationByLinearOrgId: ImpureGraphFunction< { equal: [{ path: ["webId"] }, { parameter: userAccountId }], }, - generateVersionedUrlMatchingFilter( - systemEntityTypes.linearIntegration.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.linearIntegration.entityTypeId, { + ignoreParents: true, + }), { equal: [ { - path: [ - "properties", - systemPropertyTypes.linearOrgId.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.linearOrgId.propertyTypeBaseUrl], }, { parameter: linearOrgId }, ], @@ -192,11 +166,7 @@ export const getSyncedWebsForLinearIntegration: ImpureGraphFunction< webEntity: HashEntity; }[] > -> = async ( - context, - authentication, - { linearIntegrationEntityId, includeDrafts = false }, -) => +> = async (context, authentication, { linearIntegrationEntityId, includeDrafts = false }) => queryEntitySubgraph(context, authentication, { filter: { all: [ @@ -211,9 +181,7 @@ export const getSyncedWebsForLinearIntegration: ImpureGraphFunction< equal: [ { path: ["leftEntity", "uuid"] }, { - parameter: extractEntityUuidFromEntityId( - linearIntegrationEntityId, - ), + parameter: extractEntityUuidFromEntityId(linearIntegrationEntityId), }, ], }, @@ -235,16 +203,14 @@ export const getSyncedWebsForLinearIntegration: ImpureGraphFunction< }).then(({ subgraph }) => { const syncLinearDataWithLinkEntities = getRoots(subgraph); - return syncLinearDataWithLinkEntities.map( - (syncLinearDataWithLinkEntity) => { - const webEntity = getRightEntityForLinkEntity( - subgraph, - syncLinearDataWithLinkEntity.metadata.recordId.entityId, - )![0]! as HashEntity; + return syncLinearDataWithLinkEntities.map((syncLinearDataWithLinkEntity) => { + const webEntity = getRightEntityForLinkEntity( + subgraph, + syncLinearDataWithLinkEntity.metadata.recordId.entityId, + )![0]! as HashEntity; - return { syncLinearDataWithLinkEntity, webEntity }; - }, - ); + return { syncLinearDataWithLinkEntity, webEntity }; + }); }); export const linkIntegrationToWeb: ImpureGraphFunction< @@ -258,15 +224,12 @@ export const linkIntegrationToWeb: ImpureGraphFunction< false, true > = async (context, authentication, params) => { - const { - linearIntegrationEntityId, - webEntityId, - linearTeamIds, - includeDrafts = false, - } = params; + const { linearIntegrationEntityId, webEntityId, linearTeamIds, includeDrafts = false } = params; - const { entities: existingLinkEntities } = - await queryEntities(context, authentication, { + const { entities: existingLinkEntities } = await queryEntities( + context, + authentication, + { filter: { all: [ { @@ -280,9 +243,7 @@ export const linkIntegrationToWeb: ImpureGraphFunction< equal: [ { path: ["leftEntity", "uuid"] }, { - parameter: extractEntityUuidFromEntityId( - linearIntegrationEntityId, - ), + parameter: extractEntityUuidFromEntityId(linearIntegrationEntityId), }, ], }, @@ -299,7 +260,8 @@ export const linkIntegrationToWeb: ImpureGraphFunction< temporalAxes: currentTimeInstantTemporalAxes, includeDrafts, includePermissions: false, - }); + }, + ); const properties: SyncLinearDataWith["propertiesWithMetadata"] = { value: { @@ -307,8 +269,7 @@ export const linkIntegrationToWeb: ImpureGraphFunction< value: linearTeamIds.map((linearTeamId) => ({ value: linearTeamId, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, })), }, @@ -331,17 +292,12 @@ export const linkIntegrationToWeb: ImpureGraphFunction< { op: "add", path: [teamIdPath], - property: - properties.value[ - "https://hash.ai/@h/types/property-type/linear-team-id/" - ]!, + property: properties.value["https://hash.ai/@h/types/property-type/linear-team-id/"]!, }, ], }); } else { - const linearIntegrationWebId = extractWebIdFromEntityId( - linearIntegrationEntityId, - ); + const linearIntegrationWebId = extractWebIdFromEntityId(linearIntegrationEntityId); const linkEntityUuid = generateUuid() as EntityUuid; await createLinkEntity(context, authentication, { @@ -352,9 +308,7 @@ export const linkIntegrationToWeb: ImpureGraphFunction< leftEntityId: linearIntegrationEntityId, rightEntityId: webEntityId, }, - entityTypeIds: [ - systemLinkEntityTypes.syncLinearDataWith.linkEntityTypeId, - ], + entityTypeIds: [systemLinkEntityTypes.syncLinearDataWith.linkEntityTypeId], }); } }; diff --git a/apps/hash-api/src/graph/knowledge/system-types/linear-user-secret.ts b/apps/hash-api/src/graph/knowledge/system-types/linear-user-secret.ts index 3217556a34f..f1a3110cb1c 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/linear-user-secret.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/linear-user-secret.ts @@ -1,13 +1,7 @@ import * as Sentry from "@sentry/node"; -import { - extractWebIdFromEntityId, - splitEntityId, -} from "@blockprotocol/type-system"; -import { - EntityTypeMismatchError, - NotFoundError, -} from "@local/hash-backend-utils/error"; +import { extractWebIdFromEntityId, splitEntityId } from "@blockprotocol/type-system"; +import { EntityTypeMismatchError, NotFoundError } from "@local/hash-backend-utils/error"; import { queryEntities } from "@local/hash-graph-sdk/entity"; import { currentTimeInstantTemporalAxes, @@ -20,16 +14,8 @@ import { } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-properties"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; -import type { - ActorEntityUuid, - Entity, - EntityId, - WebId, -} from "@blockprotocol/type-system"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; +import type { ActorEntityUuid, Entity, EntityId, WebId } from "@blockprotocol/type-system"; import type { VaultClient } from "@local/hash-backend-utils/vault"; import type { LinearIntegration } from "@local/hash-isomorphic-utils/system-types/linearintegration"; import type { UserSecret } from "@local/hash-isomorphic-utils/system-types/shared"; @@ -40,14 +26,8 @@ export type LinearUserSecret = { entity: Entity; }; -function assertLinearUserSecret( - entity: Entity, -): asserts entity is Entity { - if ( - !entity.metadata.entityTypeIds.includes( - systemEntityTypes.userSecret.entityTypeId, - ) - ) { +function assertLinearUserSecret(entity: Entity): asserts entity is Entity { + if (!entity.metadata.entityTypeIds.includes(systemEntityTypes.userSecret.entityTypeId)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, systemEntityTypes.userSecret.entityTypeId, @@ -56,14 +36,8 @@ function assertLinearUserSecret( } } -function assertLinearIntegration( - entity: Entity, -): asserts entity is Entity { - if ( - !entity.metadata.entityTypeIds.includes( - systemEntityTypes.linearIntegration.entityTypeId, - ) - ) { +function assertLinearIntegration(entity: Entity): asserts entity is Entity { + if (!entity.metadata.entityTypeIds.includes(systemEntityTypes.linearIntegration.entityTypeId)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, systemEntityTypes.linearIntegration.entityTypeId, @@ -78,9 +52,7 @@ export const getLinearUserSecretFromEntity: PureGraphFunction< > = ({ entity }) => { assertLinearUserSecret(entity); - const { connectionSourceName, vaultPath } = simplifyProperties( - entity.properties, - ); + const { connectionSourceName, vaultPath } = simplifyProperties(entity.properties); return { connectionSourceName, @@ -109,21 +81,17 @@ export const getLinearUserSecretByLinearOrgId: ImpureGraphFunction< equal: [{ path: ["webId"] }, { parameter: userAccountId as WebId }], }, { equal: [{ path: ["archived"] }, { parameter: false }] }, - generateVersionedUrlMatchingFilter( - systemEntityTypes.userSecret.entityTypeId, - { ignoreParents: true }, - ), - generateVersionedUrlMatchingFilter( - systemLinkEntityTypes.usesUserSecret.linkEntityTypeId, - { ignoreParents: true, pathPrefix: ["incomingLinks"] }, - ), - generateVersionedUrlMatchingFilter( - systemEntityTypes.linearIntegration.entityTypeId, - { - ignoreParents: true, - pathPrefix: ["incomingLinks", "leftEntity"], - }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.userSecret.entityTypeId, { + ignoreParents: true, + }), + generateVersionedUrlMatchingFilter(systemLinkEntityTypes.usesUserSecret.linkEntityTypeId, { + ignoreParents: true, + pathPrefix: ["incomingLinks"], + }), + generateVersionedUrlMatchingFilter(systemEntityTypes.linearIntegration.entityTypeId, { + ignoreParents: true, + pathPrefix: ["incomingLinks", "leftEntity"], + }), { equal: [ { @@ -181,55 +149,47 @@ export const getLinearSecretValueByHashWebEntityId: ImpureGraphFunction< const { hashWebEntityId, vaultClient, includeDrafts = false } = params; const [webId, webUuid] = splitEntityId(hashWebEntityId); - const { entities: linearIntegrationEntities } = await queryEntities( - context, - authentication, - { - filter: { - all: [ - generateVersionedUrlMatchingFilter( - systemLinkEntityTypes.syncLinearDataWith.linkEntityTypeId, - { - ignoreParents: true, - pathPrefix: ["outgoingLinks"], - }, - ), - { - equal: [ - { path: ["outgoingLinks", "rightEntity", "uuid"] }, - { - parameter: webUuid, - }, - ], - }, + const { entities: linearIntegrationEntities } = await queryEntities(context, authentication, { + filter: { + all: [ + generateVersionedUrlMatchingFilter( + systemLinkEntityTypes.syncLinearDataWith.linkEntityTypeId, { - equal: [ - { path: ["outgoingLinks", "rightEntity", "webId"] }, - { - parameter: webId, - }, - ], + ignoreParents: true, + pathPrefix: ["outgoingLinks"], }, - ], - }, - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts, - includePermissions: false, + ), + { + equal: [ + { path: ["outgoingLinks", "rightEntity", "uuid"] }, + { + parameter: webUuid, + }, + ], + }, + { + equal: [ + { path: ["outgoingLinks", "rightEntity", "webId"] }, + { + parameter: webId, + }, + ], + }, + ], }, - ); + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts, + includePermissions: false, + }); const integrationEntity = linearIntegrationEntities[0]; if (!integrationEntity) { - throw new NotFoundError( - `No Linear integration found for web ${hashWebEntityId}`, - ); + throw new NotFoundError(`No Linear integration found for web ${hashWebEntityId}`); } if (linearIntegrationEntities.length > 1) { - throw new Error( - `Multiple Linear integrations found for web ${hashWebEntityId}`, - ); + throw new Error(`Multiple Linear integrations found for web ${hashWebEntityId}`); } assertLinearIntegration(integrationEntity); @@ -239,14 +199,10 @@ export const getLinearSecretValueByHashWebEntityId: ImpureGraphFunction< integrationEntity.metadata.recordId.entityId, ) as ActorEntityUuid; - const secretEntity = await getLinearUserSecretByLinearOrgId( - context, - authentication, - { - linearOrgId, - userAccountId, - }, - ); + const secretEntity = await getLinearUserSecretByLinearOrgId(context, authentication, { + linearOrgId, + userAccountId, + }); const secret = await vaultClient.read<{ value: string }>({ path: secretEntity.vaultPath, diff --git a/apps/hash-api/src/graph/knowledge/system-types/notification.ts b/apps/hash-api/src/graph/knowledge/system-types/notification.ts index ffb396c9a10..ff6a4d9e268 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/notification.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/notification.ts @@ -1,13 +1,7 @@ -import { - getOutgoingLinksForEntity, - getRoots, -} from "@blockprotocol/graph/stdlib"; +import { getOutgoingLinksForEntity, getRoots } from "@blockprotocol/graph/stdlib"; import { EntityTypeMismatchError } from "@local/hash-backend-utils/error"; import { getWebMachineId } from "@local/hash-backend-utils/machine-actors"; -import { - HashLinkEntity, - queryEntitySubgraph, -} from "@local/hash-graph-sdk/entity"; +import { HashLinkEntity, queryEntitySubgraph } from "@local/hash-graph-sdk/entity"; import { currentTimeInstantTemporalAxes, generateVersionedUrlMatchingFilter, @@ -23,20 +17,14 @@ import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-proper import { createEntity, updateEntity } from "../primitive/entity"; import { createLinkEntity } from "../primitive/link-entity"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { Block } from "./block"; import type { Comment } from "./comment"; import type { Page } from "./page"; import type { Text } from "./text"; import type { User } from "./user"; import type { EntityId, VersionedUrl } from "@blockprotocol/type-system"; -import type { - CreateEntityParameters, - HashEntity, -} from "@local/hash-graph-sdk/entity"; +import type { CreateEntityParameters, HashEntity } from "@local/hash-graph-sdk/entity"; import type { ArchivedPropertyValueWithMetadata, CommentNotification as CommentNotificationEntity, @@ -62,24 +50,25 @@ export const archiveNotification: ImpureGraphFunction< false, true > = async (context, authentication, params) => { - await updateEntity< - MentionNotificationEntity | CommentNotificationEntity | NotificationEntity - >(context, authentication, { - entity: params.notification.entity, - propertyPatches: [ - { - op: "add", - path: [systemPropertyTypes.archived.propertyTypeBaseUrl], - property: { - value: true, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", - }, - } satisfies ArchivedPropertyValueWithMetadata, - }, - ], - }); + await updateEntity( + context, + authentication, + { + entity: params.notification.entity, + propertyPatches: [ + { + op: "add", + path: [systemPropertyTypes.archived.propertyTypeBaseUrl], + property: { + value: true, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/boolean/v/1", + }, + } satisfies ArchivedPropertyValueWithMetadata, + }, + ], + }, + ); }; export type MentionNotification = { @@ -89,9 +78,7 @@ export type MentionNotification = { export const isEntityMentionNotificationEntity = ( entity: HashEntity, ): entity is HashEntity => - entity.metadata.entityTypeIds.includes( - systemEntityTypes.mentionNotification.entityTypeId, - ); + entity.metadata.entityTypeIds.includes(systemEntityTypes.mentionNotification.entityTypeId); export const getMentionNotificationFromEntity: PureGraphFunction< { entity: HashEntity }, @@ -142,15 +129,11 @@ export const createMentionNotification: ImpureGraphFunction< const botAuthentication = { actorId: webMachineActorId }; - const entity = await createEntity( - context, - botAuthentication, - { - webId, - properties: { value: {} }, - entityTypeIds: [systemEntityTypes.mentionNotification.entityTypeId], - }, - ); + const entity = await createEntity(context, botAuthentication, { + webId, + properties: { value: {} }, + entityTypeIds: [systemEntityTypes.mentionNotification.entityTypeId], + }); await Promise.all( [ @@ -177,9 +160,7 @@ export const createMentionNotification: ImpureGraphFunction< leftEntityId: entity.metadata.recordId.entityId, rightEntityId: occurredInEntity.entity.metadata.recordId.entityId, }, - entityTypeIds: [ - systemLinkEntityTypes.occurredInEntity.linkEntityTypeId, - ], + entityTypeIds: [systemLinkEntityTypes.occurredInEntity.linkEntityTypeId], }), createLinkEntity(context, userAuthentication, { webId, @@ -196,12 +177,9 @@ export const createMentionNotification: ImpureGraphFunction< properties: { value: {} }, linkData: { leftEntityId: entity.metadata.recordId.entityId, - rightEntityId: - occurredInComment.entity.metadata.recordId.entityId, + rightEntityId: occurredInComment.entity.metadata.recordId.entityId, }, - entityTypeIds: [ - systemLinkEntityTypes.occurredInComment.linkEntityTypeId, - ], + entityTypeIds: [systemLinkEntityTypes.occurredInComment.linkEntityTypeId], }) : [], createLinkEntity(context, userAuthentication, { @@ -241,37 +219,32 @@ export const getMentionNotification: ImpureGraphFunction< includeDrafts = false, } = params; - const { subgraph: entitiesSubgraph } = await queryEntitySubgraph( - context, - authentication, - { - filter: { - all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.mentionNotification.entityTypeId, - { ignoreParents: true }, - ), - { - equal: [{ path: ["webId"] }, { parameter: recipient.accountId }], - }, - pageOrNotificationNotArchivedFilter, - ], - }, - traversalPaths: [ + const { subgraph: entitiesSubgraph } = await queryEntitySubgraph(context, authentication, { + filter: { + all: [ + generateVersionedUrlMatchingFilter(systemEntityTypes.mentionNotification.entityTypeId, { + ignoreParents: true, + }), { - edges: [ - { - kind: "has-left-entity", - direction: "incoming", - }, - ], + equal: [{ path: ["webId"] }, { parameter: recipient.accountId }], }, + pageOrNotificationNotArchivedFilter, ], - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts, - includePermissions: false, }, - ); + traversalPaths: [ + { + edges: [ + { + kind: "has-left-entity", + direction: "incoming", + }, + ], + }, + ], + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts, + includePermissions: false, + }); /** * @todo: move these filters into the query when it is possible to filter @@ -286,33 +259,23 @@ export const getMentionNotification: ImpureGraphFunction< ).map((linkEntity) => new HashLinkEntity(linkEntity)); const triggeredByUserLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.triggeredByUser.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.triggeredByUser.linkEntityTypeId), ); const occurredInEntityLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.occurredInEntity.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.occurredInEntity.linkEntityTypeId), ); const occurredInBlockLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.occurredInBlock.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.occurredInBlock.linkEntityTypeId), ); const occurredInTextLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.occurredInText.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.occurredInText.linkEntityTypeId), ); const occurredInCommentLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.occurredInComment.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.occurredInComment.linkEntityTypeId), ); return ( @@ -358,9 +321,7 @@ export type CommentNotification = { export const isEntityCommentNotificationEntity = ( entity: HashEntity, ): entity is HashEntity => - entity.metadata.entityTypeIds.includes( - systemEntityTypes.commentNotification.entityTypeId, - ); + entity.metadata.entityTypeIds.includes(systemEntityTypes.commentNotification.entityTypeId); export const getCommentNotificationFromEntity: PureGraphFunction< { entity: HashEntity }, @@ -432,8 +393,7 @@ export const createCommentNotification: ImpureGraphFunction< }, { rightEntityId: triggeredByComment.entity.metadata.recordId.entityId, - linkEntityTypeId: - systemLinkEntityTypes.triggeredByComment.linkEntityTypeId, + linkEntityTypeId: systemLinkEntityTypes.triggeredByComment.linkEntityTypeId, }, { rightEntityId: occurredInEntity.entity.metadata.recordId.entityId, @@ -500,61 +460,50 @@ export const getCommentNotification: ImpureGraphFunction< includeDrafts = false, } = params; - const { subgraph: entitiesSubgraph } = await queryEntitySubgraph( - context, - authentication, - { - filter: { - all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.commentNotification.entityTypeId, - { ignoreParents: true }, - ), - { - equal: [{ path: ["webId"] }, { parameter: recipient.accountId }], - }, - /** @todo: enforce the type of these links somehow */ - { - any: [ - { - exists: { - path: [ - "properties", - systemPropertyTypes.archived.propertyTypeBaseUrl, - ], - }, - }, - { - equal: [ - { - path: [ - "properties", - systemPropertyTypes.archived.propertyTypeBaseUrl, - ], - }, - { parameter: false }, - ], - }, - ], - }, - ], - }, - traversalPaths: [ + const { subgraph: entitiesSubgraph } = await queryEntitySubgraph(context, authentication, { + filter: { + all: [ + generateVersionedUrlMatchingFilter(systemEntityTypes.commentNotification.entityTypeId, { + ignoreParents: true, + }), { - // Get the outgoing links of the entities - edges: [ + equal: [{ path: ["webId"] }, { parameter: recipient.accountId }], + }, + /** @todo: enforce the type of these links somehow */ + { + any: [ + { + exists: { + path: ["properties", systemPropertyTypes.archived.propertyTypeBaseUrl], + }, + }, { - kind: "has-left-entity", - direction: "incoming", + equal: [ + { + path: ["properties", systemPropertyTypes.archived.propertyTypeBaseUrl], + }, + { parameter: false }, + ], }, ], }, ], - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts, - includePermissions: false, }, - ); + traversalPaths: [ + { + // Get the outgoing links of the entities + edges: [ + { + kind: "has-left-entity", + direction: "incoming", + }, + ], + }, + ], + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts, + includePermissions: false, + }); /** * @todo: move these filters into the query when it is possible to filter @@ -569,33 +518,23 @@ export const getCommentNotification: ImpureGraphFunction< ).map((linkEntity) => new HashLinkEntity(linkEntity)); const triggeredByUserLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.triggeredByUser.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.triggeredByUser.linkEntityTypeId), ); const occurredInEntityLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.occurredInEntity.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.occurredInEntity.linkEntityTypeId), ); const occurredInBlockLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.occurredInBlock.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.occurredInBlock.linkEntityTypeId), ); const triggeredByCommentLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.triggeredByComment.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.triggeredByComment.linkEntityTypeId), ); const repliedToCommentLink = outgoingLinks.find(({ metadata }) => - metadata.entityTypeIds.includes( - systemLinkEntityTypes.repliedToComment.linkEntityTypeId, - ), + metadata.entityTypeIds.includes(systemLinkEntityTypes.repliedToComment.linkEntityTypeId), ); return ( diff --git a/apps/hash-api/src/graph/knowledge/system-types/org-membership.ts b/apps/hash-api/src/graph/knowledge/system-types/org-membership.ts index e65c76553a5..333ec163f85 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/org-membership.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/org-membership.ts @@ -15,18 +15,10 @@ import { import { getOrgFromEntity } from "./org"; import { getUserFromEntity } from "./user"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { Org } from "./org"; import type { User } from "./user"; -import type { - ActorEntityUuid, - EntityId, - EntityUuid, - UserId, -} from "@blockprotocol/type-system"; +import type { ActorEntityUuid, EntityId, EntityUuid, UserId } from "@blockprotocol/type-system"; import type { HashLinkEntity } from "@local/hash-graph-sdk/entity"; import type { IsMemberOf } from "@local/hash-isomorphic-utils/system-types/shared"; @@ -39,9 +31,7 @@ export const getOrgMembershipFromLinkEntity: PureGraphFunction< OrgMembership > = ({ linkEntity }) => { if ( - !linkEntity.metadata.entityTypeIds.includes( - systemLinkEntityTypes.isMemberOf.linkEntityTypeId, - ) + !linkEntity.metadata.entityTypeIds.includes(systemLinkEntityTypes.isMemberOf.linkEntityTypeId) ) { throw new EntityTypeMismatchError( linkEntity.metadata.recordId.entityId, diff --git a/apps/hash-api/src/graph/knowledge/system-types/org.ts b/apps/hash-api/src/graph/knowledge/system-types/org.ts index 188e836f298..f1beb5a6cc8 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/org.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/org.ts @@ -3,10 +3,7 @@ import { extractWebIdFromEntityId, versionedUrlFromComponents, } from "@blockprotocol/type-system"; -import { - EntityTypeMismatchError, - NotFoundError, -} from "@local/hash-backend-utils/error"; +import { EntityTypeMismatchError, NotFoundError } from "@local/hash-backend-utils/error"; import { createWebMachineActorEntity, getWebMachineId, @@ -24,21 +21,10 @@ import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-proper import { logger } from "../../../logger"; import { systemAccountId } from "../../system-account"; -import { - createEntity, - getLatestEntityById, - updateEntity, -} from "../primitive/entity"; -import { - shortnameIsInvalid, - shortnameIsRestricted, - shortnameIsTaken, -} from "./account.fields"; +import { createEntity, getLatestEntityById, updateEntity } from "../primitive/entity"; +import { shortnameIsInvalid, shortnameIsRestricted, shortnameIsTaken } from "./account.fields"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { ActorId, EntityId, @@ -60,14 +46,11 @@ export type Org = { entity: HashEntity; }; -function assertOrganizationEntity( - entity: HashEntity, -): asserts entity is HashEntity { +function assertOrganizationEntity(entity: HashEntity): asserts entity is HashEntity { if ( !entity.metadata.entityTypeIds.some( (entityTypeId) => - extractBaseUrl(entityTypeId) === - systemEntityTypes.organization.entityTypeBaseUrl, + extractBaseUrl(entityTypeId) === systemEntityTypes.organization.entityTypeBaseUrl, ) ) { throw new EntityTypeMismatchError( @@ -78,15 +61,10 @@ function assertOrganizationEntity( } } -export const getOrgFromEntity: PureGraphFunction< - { entity: HashEntity }, - Org -> = ({ entity }) => { +export const getOrgFromEntity: PureGraphFunction<{ entity: HashEntity }, Org> = ({ entity }) => { assertOrganizationEntity(entity); - const { organizationName: orgName, shortname } = simplifyProperties( - entity.properties, - ); + const { organizationName: orgName, shortname } = simplifyProperties(entity.properties); return { webId: extractWebIdFromEntityId(entity.metadata.recordId.entityId), @@ -135,9 +113,7 @@ export const createOrg: ImpureGraphFunction< (!bypassShortnameValidation && shortnameIsRestricted({ shortname })) || (await shortnameIsTaken(ctx, authentication, { shortname })) ) { - throw new Error( - `An account or an account group with shortname "${shortname}" already exists.`, - ); + throw new Error(`An account or an account group with shortname "${shortname}" already exists.`); } const trimmedName = name.trim(); @@ -154,9 +130,7 @@ export const createOrg: ImpureGraphFunction< webId: orgWebId, }).then((maybeMachineId) => { if (!maybeMachineId) { - throw new NotFoundError( - `Failed to get machine for org ID: ${orgWebId}`, - ); + throw new NotFoundError(`Failed to get machine for org ID: ${orgWebId}`); } return maybeMachineId; }); @@ -193,15 +167,13 @@ export const createOrg: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/shortname/": { value: shortname.trim().toLowerCase(), metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/organization-name/": { value: trimmedName, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, ...(websiteUrl @@ -281,10 +253,11 @@ export const createOrg: ImpureGraphFunction< * * @param params.entityId - the entity id of the organization */ -export const getOrgById: ImpureGraphFunction< - { entityId: EntityId }, - Promise -> = async (ctx, authentication, { entityId }) => { +export const getOrgById: ImpureGraphFunction<{ entityId: EntityId }, Promise> = async ( + ctx, + authentication, + { entityId }, +) => { const entity = await getLatestEntityById(ctx, authentication, { entityId, }); @@ -315,10 +288,7 @@ export const getOrgByShortname: ImpureGraphFunction< { equal: [ { - path: [ - "properties", - systemPropertyTypes.shortname.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.shortname.propertyTypeBaseUrl], }, { parameter: params.shortname.trim().toLowerCase() }, ], @@ -377,8 +347,7 @@ export const updateOrgName: ImpureGraphFunction< property: { value: trimmedName, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, } satisfies OrganizationNamePropertyValueWithMetadata, }, diff --git a/apps/hash-api/src/graph/knowledge/system-types/page.ts b/apps/hash-api/src/graph/knowledge/system-types/page.ts index 5c7cb1e040b..e765894cd75 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/page.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/page.ts @@ -28,17 +28,11 @@ import { getLatestEntityById, updateEntity, } from "../primitive/entity"; -import { - createLinkEntity, - getLinkEntityRightEntity, -} from "../primitive/link-entity"; +import { createLinkEntity, getLinkEntityRightEntity } from "../primitive/link-entity"; import { getBlockComments, getBlockFromEntity } from "./block"; import { addBlockToBlockCollection } from "./block-collection"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { Block } from "./block"; import type { Comment } from "./comment"; import type { EntityId, WebId } from "@blockprotocol/type-system"; @@ -60,9 +54,7 @@ export type Page = { entity: HashEntity; }; -function assertPageEntity( - entity: HashEntity, -): asserts entity is HashEntity { +function assertPageEntity(entity: HashEntity): asserts entity is HashEntity { if (!includesPageEntityTypeId(entity.metadata.entityTypeIds)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, @@ -72,14 +64,10 @@ function assertPageEntity( } } -export const getPageFromEntity: PureGraphFunction< - { entity: HashEntity }, - Page -> = ({ entity }) => { +export const getPageFromEntity: PureGraphFunction<{ entity: HashEntity }, Page> = ({ entity }) => { assertPageEntity(entity); - const { title, summary, fractionalIndex, icon, archived } = - simplifyProperties(entity.properties); + const { title, summary, fractionalIndex, icon, archived } = simplifyProperties(entity.properties); return { title, @@ -137,15 +125,13 @@ export const createPage: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/title/": { value: title, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/fractional-index/": { value: fractionalIndex, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, ...(summary !== undefined @@ -153,8 +139,7 @@ export const createPage: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/summary/": { value: summary, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, } @@ -182,8 +167,10 @@ export const createPage: ImpureGraphFunction< type === "document" ? { indexPosition: { - "https://hash.ai/@h/types/property-type/fractional-index/": - generateKeyBetween(null, null), + "https://hash.ai/@h/types/property-type/fractional-index/": generateKeyBetween( + null, + null, + ), }, } : { @@ -214,8 +201,7 @@ export const getPageParentPage: ImpureGraphFunction< > = async (ctx, authentication, { page }) => { const parentPageLinks = await getEntityOutgoingLinks(ctx, authentication, { entityId: page.entity.metadata.recordId.entityId, - linkEntityTypeVersionedUrl: - systemLinkEntityTypes.hasParent.linkEntityTypeId, + linkEntityTypeVersionedUrl: systemLinkEntityTypes.hasParent.linkEntityTypeId, }); const [parentPageLink, ...unexpectedParentPageLinks] = parentPageLinks; @@ -254,9 +240,7 @@ export const isPageArchived: ImpureGraphFunction< const parentPage = await getPageParentPage(ctx, authentication, { page }); - return parentPage - ? await isPageArchived(ctx, authentication, { page: parentPage }) - : false; + return parentPage ? await isPageArchived(ctx, authentication, { page: parentPage }) : false; }; /** @@ -293,10 +277,7 @@ export const getAllPagesInWorkspace: ImpureGraphFunction< return await Promise.all( pages.map(async (page) => { - if ( - !includeArchived && - (await isPageArchived(ctx, authentication, { page })) - ) { + if (!includeArchived && (await isPageArchived(ctx, authentication, { page }))) { return []; } return page; @@ -321,10 +302,7 @@ export const pageHasParentPage: ImpureGraphFunction< > = async (ctx, authentication, params) => { const { page, parentPage } = params; - if ( - page.entity.metadata.recordId.entityId === - parentPage.entity.metadata.recordId.entityId - ) { + if (page.entity.metadata.recordId.entityId === parentPage.entity.metadata.recordId.entityId) { throw new Error("A page cannot be the parent of itself"); } @@ -337,8 +315,7 @@ export const pageHasParentPage: ImpureGraphFunction< } if ( - actualParentPage.entity.metadata.recordId.entityId === - page.entity.metadata.recordId.entityId + actualParentPage.entity.metadata.recordId.entityId === page.entity.metadata.recordId.entityId ) { return true; } @@ -366,8 +343,7 @@ export const removeParentPage: ImpureGraphFunction< const { page } = params; const parentPageLinks = await getEntityOutgoingLinks(ctx, authentication, { entityId: page.entity.metadata.recordId.entityId, - linkEntityTypeVersionedUrl: - systemLinkEntityTypes.hasParent.linkEntityTypeId, + linkEntityTypeVersionedUrl: systemLinkEntityTypes.hasParent.linkEntityTypeId, }); const [parentPageLink, ...unexpectedParentPageLinks] = parentPageLinks; @@ -454,8 +430,7 @@ export const setPageParentPage: ImpureGraphFunction< property: { value: newIndex, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, } satisfies FractionalIndexPropertyValueWithMetadata, }, @@ -477,39 +452,28 @@ export const getPageBlocks: ImpureGraphFunction< { pageEntityId: EntityId; type: "canvas" | "document" }, Promise< { - linkEntity: HashLinkEntity< - HasIndexedContent | HasSpatiallyPositionedContent - >; + linkEntity: HashLinkEntity; rightEntity: Block; }[] >, false, true > = async (ctx, authentication, { pageEntityId, type }) => { - const outgoingBlockDataLinks = (await getEntityOutgoingLinks( - ctx, - authentication, - { - entityId: pageEntityId, - linkEntityTypeVersionedUrl: - type === "document" - ? systemLinkEntityTypes.hasIndexedContent.linkEntityTypeId - : systemLinkEntityTypes.hasSpatiallyPositionedContent - .linkEntityTypeId, - }, - )) as - | HashLinkEntity[] - | HashLinkEntity[]; + const outgoingBlockDataLinks = (await getEntityOutgoingLinks(ctx, authentication, { + entityId: pageEntityId, + linkEntityTypeVersionedUrl: + type === "document" + ? systemLinkEntityTypes.hasIndexedContent.linkEntityTypeId + : systemLinkEntityTypes.hasSpatiallyPositionedContent.linkEntityTypeId, + })) as HashLinkEntity[] | HashLinkEntity[]; return await Promise.all( - outgoingBlockDataLinks - .sort(sortBlockCollectionLinks) - .map(async (linkEntity) => ({ + outgoingBlockDataLinks.sort(sortBlockCollectionLinks).map(async (linkEntity) => ({ + linkEntity, + rightEntity: await getLinkEntityRightEntity(ctx, authentication, { linkEntity, - rightEntity: await getLinkEntityRightEntity(ctx, authentication, { - linkEntity, - }).then((entity) => getBlockFromEntity({ entity })), - })), + }).then((entity) => getBlockFromEntity({ entity })), + })), ); }; @@ -530,12 +494,8 @@ export const getPageComments: ImpureGraphFunction< }); const comments = await Promise.all( - blocks.map(({ rightEntity }) => - getBlockComments(ctx, authentication, { block: rightEntity }), - ), + blocks.map(({ rightEntity }) => getBlockComments(ctx, authentication, { block: rightEntity })), ); - return comments - .flat() - .filter((comment) => !comment.resolvedAt && !comment.deletedAt); + return comments.flat().filter((comment) => !comment.resolvedAt && !comment.deletedAt); }; diff --git a/apps/hash-api/src/graph/knowledge/system-types/text.ts b/apps/hash-api/src/graph/knowledge/system-types/text.ts index 8dcf562383e..5107245b33b 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/text.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/text.ts @@ -22,10 +22,7 @@ import { getCommentById } from "./comment"; import { getPageFromEntity } from "./page"; import { getUser } from "./user"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { Block } from "./block"; import type { Comment } from "./comment"; import type { Page } from "./page"; @@ -39,12 +36,8 @@ export type Text = { entity: HashEntity; }; -function assertTextEntity( - entity: HashEntity, -): asserts entity is HashEntity { - if ( - !entity.metadata.entityTypeIds.includes(systemEntityTypes.text.entityTypeId) - ) { +function assertTextEntity(entity: HashEntity): asserts entity is HashEntity { + if (!entity.metadata.entityTypeIds.includes(systemEntityTypes.text.entityTypeId)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, systemEntityTypes.text.entityTypeId, @@ -53,10 +46,7 @@ function assertTextEntity( } } -export const getTextFromEntity: PureGraphFunction< - { entity: HashEntity }, - Text -> = ({ entity }) => { +export const getTextFromEntity: PureGraphFunction<{ entity: HashEntity }, Text> = ({ entity }) => { assertTextEntity(entity); const { textualContent } = simplifyProperties(entity.properties); @@ -74,10 +64,11 @@ export const getTextFromEntity: PureGraphFunction< * * @param params.entityId - the entity id of the text */ -export const getTextById: ImpureGraphFunction< - { entityId: EntityId }, - Promise -> = async (ctx, authentication, { entityId }) => { +export const getTextById: ImpureGraphFunction<{ entityId: EntityId }, Promise> = async ( + ctx, + authentication, + { entityId }, +) => { const entity = await getLatestEntityById(ctx, authentication, { entityId, }); @@ -96,55 +87,46 @@ export const getPageAndBlockByText: ImpureGraphFunction< > = async (context, authentication, params) => { const { text, includeDrafts = false } = params; - const textEntityUuid = extractEntityUuidFromEntityId( - text.entity.metadata.recordId.entityId, - ); + const textEntityUuid = extractEntityUuidFromEntityId(text.entity.metadata.recordId.entityId); - const [ - matchingBlockDataLinksWithTextAtDepthOne, - matchingBlockDataLinksWithTextAtDepthTwo, - ] = await Promise.all([ - queryEntities(context, authentication, { - filter: { - all: [ - generateVersionedUrlMatchingFilter( - systemLinkEntityTypes.hasData.linkEntityTypeId, - { ignoreParents: true }, - ), - { - equal: [ - { path: ["rightEntity", "uuid"] }, - { parameter: textEntityUuid }, - ], - }, - ], - }, - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts, - includePermissions: false, - }).then(({ entities }) => entities.filter(isEntityLinkEntity)), - queryEntities(context, authentication, { - filter: { - all: [ - generateVersionedUrlMatchingFilter( - systemLinkEntityTypes.hasData.linkEntityTypeId, - { ignoreParents: true }, - ), - { - equal: [ - { - path: ["rightEntity", "outgoingLinks", "rightEntity", "uuid"], - }, - { parameter: textEntityUuid }, - ], - }, - ], - }, - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts, - includePermissions: false, - }).then(({ entities }) => entities.filter(isEntityLinkEntity)), - ]); + const [matchingBlockDataLinksWithTextAtDepthOne, matchingBlockDataLinksWithTextAtDepthTwo] = + await Promise.all([ + queryEntities(context, authentication, { + filter: { + all: [ + generateVersionedUrlMatchingFilter(systemLinkEntityTypes.hasData.linkEntityTypeId, { + ignoreParents: true, + }), + { + equal: [{ path: ["rightEntity", "uuid"] }, { parameter: textEntityUuid }], + }, + ], + }, + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts, + includePermissions: false, + }).then(({ entities }) => entities.filter(isEntityLinkEntity)), + queryEntities(context, authentication, { + filter: { + all: [ + generateVersionedUrlMatchingFilter(systemLinkEntityTypes.hasData.linkEntityTypeId, { + ignoreParents: true, + }), + { + equal: [ + { + path: ["rightEntity", "outgoingLinks", "rightEntity", "uuid"], + }, + { parameter: textEntityUuid }, + ], + }, + ], + }, + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts, + includePermissions: false, + }).then(({ entities }) => entities.filter(isEntityLinkEntity)), + ]); /** @todo: unify these in a single structural query when it becomes possible */ const matchingBlockDataLinks = [ @@ -182,9 +164,7 @@ export const getPageAndBlockByText: ImpureGraphFunction< equal: [ { path: ["outgoingLinks", "uuid"] }, { - parameter: extractEntityUuidFromEntityId( - metadata.recordId.entityId, - ), + parameter: extractEntityUuidFromEntityId(metadata.recordId.entityId), }, ], })), @@ -194,16 +174,13 @@ export const getPageAndBlockByText: ImpureGraphFunction< temporalAxes: currentTimeInstantTemporalAxes, includeDrafts, includePermissions: false, - }).then(({ entities }) => - entities.map((entity) => getPageFromEntity({ entity })), - ); + }).then(({ entities }) => entities.map((entity) => getPageFromEntity({ entity }))); const page = pageEntities[0]; if (page) { const blockEntityId = matchingContainsLinks.find( - ({ linkData }) => - linkData.leftEntityId === page.entity.metadata.recordId.entityId, + ({ linkData }) => linkData.leftEntityId === page.entity.metadata.recordId.entityId, )!.linkData.rightEntityId; const block = await getBlockById(context, authentication, { @@ -225,27 +202,21 @@ export const getCommentByText: ImpureGraphFunction< Promise > = async (context, authentication, params) => { const { text, includeDrafts = false } = params; - const textEntityUuid = extractEntityUuidFromEntityId( - text.entity.metadata.recordId.entityId, - ); + const textEntityUuid = extractEntityUuidFromEntityId(text.entity.metadata.recordId.entityId); const matchingHasTextLinks = await queryEntities(context, authentication, { filter: { all: [ - generateVersionedUrlMatchingFilter( - systemLinkEntityTypes.hasText.linkEntityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemLinkEntityTypes.hasText.linkEntityTypeId, { + ignoreParents: true, + }), { - equal: [ - { path: ["rightEntity", "uuid"] }, - { parameter: textEntityUuid }, - ], + equal: [{ path: ["rightEntity", "uuid"] }, { parameter: textEntityUuid }], }, - generateVersionedUrlMatchingFilter( - systemEntityTypes.comment.entityTypeId, - { ignoreParents: true, pathPrefix: ["leftEntity"] }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.comment.entityTypeId, { + ignoreParents: true, + pathPrefix: ["leftEntity"], + }), ], }, temporalAxes: currentTimeInstantTemporalAxes, @@ -280,8 +251,7 @@ export const getMentionedUsersInTextualContent: ImpureGraphFunction< Promise > = async (context, authentication, { textualContent }) => { const mentionTextualContent = textualContent.filter( - (token): token is Extract => - token.tokenType === "mention", + (token): token is Extract => token.tokenType === "mention", ); const mentionedUsers = await Promise.all( @@ -289,8 +259,7 @@ export const getMentionedUsersInTextualContent: ImpureGraphFunction< .filter(({ mentionType }) => mentionType === "user") // Filter duplicate user mentions (users that were mentioned more than once) .filter( - (mention, i, all) => - all.findIndex(({ entityId }) => entityId === mention.entityId) === i, + (mention, i, all) => all.findIndex(({ entityId }) => entityId === mention.entityId) === i, ) .map(async ({ entityId }) => { const user = await getUser(context, authentication, { entityId }); diff --git a/apps/hash-api/src/graph/knowledge/system-types/user-secret.ts b/apps/hash-api/src/graph/knowledge/system-types/user-secret.ts index 2b8928b9b3e..9457a0f1b79 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/user-secret.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/user-secret.ts @@ -17,10 +17,7 @@ import type { UserId, WebId, } from "@blockprotocol/type-system"; -import type { - UserSecretService, - VaultClient, -} from "@local/hash-backend-utils/vault"; +import type { UserSecretService, VaultClient } from "@local/hash-backend-utils/vault"; import type { GraphApi } from "@local/hash-graph-client"; import type { UsesUserSecret } from "@local/hash-isomorphic-utils/system-types/google/shared"; import type { UserSecret } from "@local/hash-isomorphic-utils/system-types/shared"; @@ -66,9 +63,7 @@ type CreateUserSecretParams = { * - the ONLY _editor_ of both the secret and the link is the provided managingBotAccountId. * - the ONLY _viewer_ of the secret and the link is the userAccountId (apart from the managingBotAccountId). */ -export const createUserSecret = async < - T extends object = Record<"value", string>, ->( +export const createUserSecret = async >( params: CreateUserSecretParams, ): Promise => { const { @@ -96,8 +91,7 @@ export const createUserSecret = async < "https://hash.ai/@h/types/property-type/connection-source-name/": { value: service, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/expired-at/": { @@ -109,8 +103,7 @@ export const createUserSecret = async < "https://hash.ai/@h/types/property-type/vault-path/": { value: vaultPath, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, }, @@ -148,11 +141,7 @@ export const createUserSecret = async < await Promise.all( linkAndSecretPairs.flatMap(({ userSecret, usesUserSecretLink }) => [ userSecret.archive(graphApi, managingBotAuthentication, provenance), - usesUserSecretLink.archive( - graphApi, - managingBotAuthentication, - provenance, - ), + usesUserSecretLink.archive(graphApi, managingBotAuthentication, provenance), ]), ); } @@ -184,32 +173,28 @@ export const createUserSecret = async < ); /** Link the user secret to the Google Account */ - await createLinkEntity( - { graphApi, provenance }, - authentication, - { - webId: userAccountId as WebId, - entityUuid: usesUserSecretEntityUuid, - properties: { value: {} }, - linkData: { - leftEntityId: sourceIntegrationEntityId, - rightEntityId: userSecretEntity.metadata.recordId.entityId, - }, - entityTypeIds: [systemLinkEntityTypes.usesUserSecret.linkEntityTypeId], - policies: [ - { - name: `user-secret-entity-${usesUserSecretEntityUuid}`, - principal: { - type: "actor", - actorType: "machine", - id: managingBotAccountId, - }, - effect: "permit", - actions: ["viewEntity", "updateEntity", "archiveEntity"], - }, - ], + await createLinkEntity({ graphApi, provenance }, authentication, { + webId: userAccountId as WebId, + entityUuid: usesUserSecretEntityUuid, + properties: { value: {} }, + linkData: { + leftEntityId: sourceIntegrationEntityId, + rightEntityId: userSecretEntity.metadata.recordId.entityId, }, - ); + entityTypeIds: [systemLinkEntityTypes.usesUserSecret.linkEntityTypeId], + policies: [ + { + name: `user-secret-entity-${usesUserSecretEntityUuid}`, + principal: { + type: "actor", + actorType: "machine", + id: managingBotAccountId, + }, + effect: "permit", + actions: ["viewEntity", "updateEntity", "archiveEntity"], + }, + ], + }); return userSecretEntity.metadata.recordId.entityId; }; diff --git a/apps/hash-api/src/graph/knowledge/system-types/user.ts b/apps/hash-api/src/graph/knowledge/system-types/user.ts index 1da7489d056..e972e2980e7 100644 --- a/apps/hash-api/src/graph/knowledge/system-types/user.ts +++ b/apps/hash-api/src/graph/knowledge/system-types/user.ts @@ -6,20 +6,10 @@ import { } from "@blockprotocol/type-system"; import { EntityTypeMismatchError } from "@local/hash-backend-utils/error"; import { createWebMachineActorEntity } from "@local/hash-backend-utils/machine-actors"; -import { - type HashEntity, - queryEntities, - queryEntitySubgraph, -} from "@local/hash-graph-sdk/entity"; -import { - addActorGroupMember, - createUserActor, -} from "@local/hash-graph-sdk/principal/actor-group"; +import { type HashEntity, queryEntities, queryEntitySubgraph } from "@local/hash-graph-sdk/entity"; +import { addActorGroupMember, createUserActor } from "@local/hash-graph-sdk/principal/actor-group"; import { getInstanceAdminsTeam } from "@local/hash-graph-sdk/principal/hash-instance-admins"; -import { - type FeatureFlag, - featureFlags, -} from "@local/hash-isomorphic-utils/feature-flags"; +import { type FeatureFlag, featureFlags } from "@local/hash-isomorphic-utils/feature-flags"; import { currentTimeInstantTemporalAxes, generateVersionedUrlMatchingFilter, @@ -31,37 +21,20 @@ import { } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-properties"; -import { - getVerifiedEmailsFromKratosIdentity, - kratosIdentityApi, -} from "../../../auth/ory-kratos"; +import { getVerifiedEmailsFromKratosIdentity, kratosIdentityApi } from "../../../auth/ory-kratos"; import { getPendingOrgInvitationsFromSubgraph } from "../../../graphql/resolvers/knowledge/org/shared"; import { logger } from "../../../logger"; import { systemAccountId } from "../../system-account"; -import { - createEntity, - getEntityOutgoingLinks, - getLatestEntityById, -} from "../primitive/entity"; -import { - shortnameIsInvalid, - shortnameIsRestricted, - shortnameIsTaken, -} from "./account.fields"; +import { createEntity, getEntityOutgoingLinks, getLatestEntityById } from "../primitive/entity"; +import { shortnameIsInvalid, shortnameIsRestricted, shortnameIsTaken } from "./account.fields"; import { createOrgMembership, getOrgMembershipFromLinkEntity, getOrgMembershipOrg, } from "./org-membership"; -import type { - KratosUserIdentity, - KratosUserIdentityTraits, -} from "../../../auth/ory-kratos"; -import type { - ImpureGraphFunction, - PureGraphFunction, -} from "../../context-types"; +import type { KratosUserIdentity, KratosUserIdentityTraits } from "../../../auth/ory-kratos"; +import type { ImpureGraphFunction, PureGraphFunction } from "../../context-types"; import type { OrgMembership } from "./org-membership"; import type { EntityId, EntityUuid, UserId } from "@blockprotocol/type-system"; import type { Filter } from "@local/hash-graph-client"; @@ -94,14 +67,11 @@ function assertFeatureFlags( function isUserEntity(entity: HashEntity): entity is HashEntity { return entity.metadata.entityTypeIds.some( - (entityTypeId) => - extractBaseUrl(entityTypeId) === systemEntityTypes.user.entityTypeBaseUrl, + (entityTypeId) => extractBaseUrl(entityTypeId) === systemEntityTypes.user.entityTypeBaseUrl, ); } -function assertUserEntity( - entity: HashEntity, -): asserts entity is HashEntity { +function assertUserEntity(entity: HashEntity): asserts entity is HashEntity { if (!isUserEntity(entity)) { throw new EntityTypeMismatchError( entity.metadata.recordId.entityId, @@ -115,26 +85,23 @@ function assertUserEntity( * Fetch user emails from Kratos identity traits. * This is the source of truth for emails since DB-level masking hides them from non-owners. */ -const getEmailsFromKratos = async ( - kratosIdentityId: string, -): Promise => { +const getEmailsFromKratos = async (kratosIdentityId: string): Promise => { try { const { data: identity } = await kratosIdentityApi.getIdentity({ id: kratosIdentityId, }); return (identity.traits as KratosUserIdentityTraits).emails; } catch (error) { - logger.warn( - `Failed to fetch emails from Kratos for identity ${kratosIdentityId}: ${error}`, - ); + logger.warn(`Failed to fetch emails from Kratos for identity ${kratosIdentityId}: ${error}`); return []; } }; -export const getUserVerifiedEmails: ImpureGraphFunction< - { user: User }, - Promise -> = async (_, __, { user }) => { +export const getUserVerifiedEmails: ImpureGraphFunction<{ user: User }, Promise> = async ( + _, + __, + { user }, +) => { const { data: identity } = await kratosIdentityApi.getIdentity({ id: user.kratosIdentityId, }); @@ -174,10 +141,7 @@ export const checkEmailVerificationAndUsageStatus = async ( } }; -export const getUserFromEntity: PureGraphFunction< - { entity: HashEntity }, - User -> = ({ entity }) => { +export const getUserFromEntity: PureGraphFunction<{ entity: HashEntity }, User> = ({ entity }) => { assertUserEntity(entity); const { @@ -195,9 +159,7 @@ export const getUserFromEntity: PureGraphFunction< assertFeatureFlags(enabledFeatureFlags); return { - accountId: extractWebIdFromEntityId( - entity.metadata.recordId.entityId, - ) as UserId, + accountId: extractWebIdFromEntityId(entity.metadata.recordId.entityId) as UserId, displayName, emails, enabledFeatureFlags, @@ -233,8 +195,7 @@ export const getUser: ImpureGraphFunction< const knownShortname = "shortname" in params ? params.shortname : null; let emails = "emails" in params ? params.emails : undefined; - const kratosIdentityId = - "kratosIdentityId" in params ? params.kratosIdentityId : null; + const kratosIdentityId = "kratosIdentityId" in params ? params.kratosIdentityId : null; let entity: HashEntity; @@ -258,10 +219,7 @@ export const getUser: ImpureGraphFunction< queryFilter = { equal: [ { - path: [ - "properties", - systemPropertyTypes.kratosIdentityId.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.kratosIdentityId.propertyTypeBaseUrl], }, { parameter: kratosIdentityId }, ], @@ -270,10 +228,7 @@ export const getUser: ImpureGraphFunction< queryFilter = { equal: [ { - path: [ - "properties", - systemPropertyTypes.shortname.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.shortname.propertyTypeBaseUrl], }, { parameter: knownShortname?.trim().toLowerCase() }, ], @@ -285,12 +240,9 @@ export const getUser: ImpureGraphFunction< } = await queryEntities(context, authentication, { filter: { all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.user.entityTypeId, - { - ignoreParents: true, - }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.user.entityTypeId, { + ignoreParents: true, + }), queryFilter, ], }, @@ -314,26 +266,20 @@ export const getUser: ImpureGraphFunction< emails ??= atLeastOne( await getEmailsFromKratos( - entity.properties[ - "https://hash.ai/@h/types/property-type/kratos-identity-id/" - ], + entity.properties["https://hash.ai/@h/types/property-type/kratos-identity-id/"], ), ); if (!emails) { throw new Error( `Critical: No email found for user with kratos identity id: ${ - entity.properties[ - "https://hash.ai/@h/types/property-type/kratos-identity-id/" - ] + entity.properties["https://hash.ai/@h/types/property-type/kratos-identity-id/"] }`, ); } entity.properties["https://hash.ai/@h/types/property-type/email/"] = emails; - entity.propertiesMetadata.value[ - systemPropertyTypes.email.propertyTypeBaseUrl - ] ??= { + entity.propertiesMetadata.value[systemPropertyTypes.email.propertyTypeBaseUrl] ??= { value: [ { metadata: { @@ -383,9 +329,7 @@ export const createUser: ImpureGraphFunction< }); if (existingUserWithKratosIdentityId) { - throw new Error( - `A user entity with kratos identity id "${kratosIdentityId}" already exists.`, - ); + throw new Error(`A user entity with kratos identity id "${kratosIdentityId}" already exists.`); } if (shortname) { @@ -397,22 +341,16 @@ export const createUser: ImpureGraphFunction< shortnameIsRestricted({ shortname }) || (await shortnameIsTaken(ctx, authentication, { shortname })) ) { - throw new Error( - `An account with shortname "${shortname}" already exists.`, - ); + throw new Error(`An account with shortname "${shortname}" already exists.`); } } const userShouldHavePermissionsOnWeb = !!shortname && !!displayName; - const { userId, machineId } = await createUserActor( - ctx.graphApi, - authentication, - { - shortname, - registrationComplete: userShouldHavePermissionsOnWeb, - }, - ); + const { userId, machineId } = await createUserActor(ctx.graphApi, authentication, { + shortname, + registrationComplete: userShouldHavePermissionsOnWeb, + }); await createWebMachineActorEntity(ctx, { webId: userId, @@ -433,8 +371,7 @@ export const createUser: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/kratos-identity-id/": { value: kratosIdentityId, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, ...(shortname !== undefined @@ -442,22 +379,19 @@ export const createUser: ImpureGraphFunction< "https://hash.ai/@h/types/property-type/shortname/": { value: shortname.trim().toLowerCase(), metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, } : {}), ...(displayName !== undefined ? { - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": - { - value: displayName, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": { + value: displayName, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, + }, } : {}), ...(enabledFeatureFlags !== undefined @@ -466,8 +400,7 @@ export const createUser: ImpureGraphFunction< value: enabledFeatureFlags.map((flag) => ({ value: flag, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, })), }, @@ -586,15 +519,10 @@ export const getUserOrgMemberships: ImpureGraphFunction< { userEntityId: EntityId }, Promise > = async (ctx, authentication, { userEntityId }) => { - const outgoingOrgMembershipLinkEntities = await getEntityOutgoingLinks( - ctx, - authentication, - { - entityId: userEntityId, - linkEntityTypeVersionedUrl: - systemLinkEntityTypes.isMemberOf.linkEntityTypeId, - }, - ); + const outgoingOrgMembershipLinkEntities = await getEntityOutgoingLinks(ctx, authentication, { + entityId: userEntityId, + linkEntityTypeVersionedUrl: systemLinkEntityTypes.isMemberOf.linkEntityTypeId, + }); return outgoingOrgMembershipLinkEntities.map((linkEntity) => getOrgMembershipFromLinkEntity({ linkEntity }), @@ -611,11 +539,7 @@ export const isUserMemberOfOrg: ImpureGraphFunction< { userEntityId: EntityId; orgEntityUuid: EntityUuid }, Promise > = async (ctx, authentication, params) => { - const orgMemberships = await getUserOrgMemberships( - ctx, - authentication, - params, - ); + const orgMemberships = await getUserOrgMemberships(ctx, authentication, params); const orgs = await Promise.all( orgMemberships.map((orgMembership) => @@ -627,8 +551,7 @@ export const isUserMemberOfOrg: ImpureGraphFunction< return !!orgs.find( (org) => - extractEntityUuidFromEntityId(org.entity.metadata.recordId.entityId) === - params.orgEntityUuid, + extractEntityUuidFromEntityId(org.entity.metadata.recordId.entityId) === params.orgEntityUuid, ); }; @@ -654,9 +577,7 @@ export const getUserPendingInvitations: ImpureGraphFunction< temporalAxes: currentTimeInstantTemporalAxes, filter: { all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.invitation.entityTypeId, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.invitation.entityTypeId), { equal: [ { @@ -670,10 +591,7 @@ export const getUserPendingInvitations: ImpureGraphFunction< ...user.emails.map((email) => ({ equal: [ { - path: [ - "properties", - systemPropertyTypes.email.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.email.propertyTypeBaseUrl], }, { parameter: email }, ], @@ -683,10 +601,7 @@ export const getUserPendingInvitations: ImpureGraphFunction< { equal: [ { - path: [ - "properties", - systemPropertyTypes.shortname.propertyTypeBaseUrl, - ], + path: ["properties", systemPropertyTypes.shortname.propertyTypeBaseUrl], }, { parameter: user.shortname }, ], diff --git a/apps/hash-api/src/graph/ontology/primitive/data-type.ts b/apps/hash-api/src/graph/ontology/primitive/data-type.ts index 7480ebf2343..08995f17e4f 100644 --- a/apps/hash-api/src/graph/ontology/primitive/data-type.ts +++ b/apps/hash-api/src/graph/ontology/primitive/data-type.ts @@ -20,10 +20,7 @@ import type { VersionedUrl, WebId, } from "@blockprotocol/type-system"; -import type { - ArchiveDataTypeParams, - UnarchiveDataTypeParams, -} from "@local/hash-graph-client"; +import type { ArchiveDataTypeParams, UnarchiveDataTypeParams } from "@local/hash-graph-client"; import type { UserPermissionsOnDataType } from "@local/hash-graph-sdk/authorization"; import type { ConstructDataTypeParams, @@ -78,17 +75,14 @@ export const createDataType: ImpureGraphFunction< ...params.schema, }; - const { data: metadata } = await graphApi.createDataType( - authentication.actorId, - { - schema, - provenance: { - ...ctx.provenance, - ...params.provenance, - }, - conversions: conversions ?? {}, + const { data: metadata } = await graphApi.createDataType(authentication.actorId, { + schema, + provenance: { + ...ctx.provenance, + ...params.provenance, }, - ); + conversions: conversions ?? {}, + }); return { schema, metadata: metadata as unknown as DataTypeMetadata }; }; @@ -140,9 +134,7 @@ export const updateDataType: ImpureGraphFunction< ...schema, // TODO: Avoid casting through `unknown` when new codegen is in place // see https://linear.app/hash/issue/H-4463/utilize-new-codegen-and-replace-custom-defined-node-types - $id: ontologyTypeRecordIdToVersionedUrl( - recordId as unknown as OntologyTypeRecordId, - ), + $id: ontologyTypeRecordIdToVersionedUrl(recordId as unknown as OntologyTypeRecordId), }, // TODO: Avoid casting through `unknown` when new codegen is in place // see https://linear.app/hash/issue/H-4463/utilize-new-codegen-and-replace-custom-defined-node-types @@ -160,10 +152,7 @@ export const archiveDataType: ImpureGraphFunction< ArchiveDataTypeParams, Promise > = async ({ graphApi }, { actorId }, params) => { - const { data: temporalMetadata } = await graphApi.archiveDataType( - actorId, - params, - ); + const { data: temporalMetadata } = await graphApi.archiveDataType(actorId, params); return temporalMetadata as OntologyTemporalMetadata; }; diff --git a/apps/hash-api/src/graph/ontology/primitive/entity-type.ts b/apps/hash-api/src/graph/ontology/primitive/entity-type.ts index f06d4001854..a6d69b96801 100644 --- a/apps/hash-api/src/graph/ontology/primitive/entity-type.ts +++ b/apps/hash-api/src/graph/ontology/primitive/entity-type.ts @@ -4,10 +4,7 @@ import { } from "@blockprotocol/type-system"; import { NotFoundError } from "@local/hash-backend-utils/error"; import { publicUserAccountId } from "@local/hash-backend-utils/public-user-account-id"; -import { - getEntityTypeById, - hasPermissionForEntityTypes, -} from "@local/hash-graph-sdk/entity-type"; +import { getEntityTypeById, hasPermissionForEntityTypes } from "@local/hash-graph-sdk/entity-type"; import { currentTimeInstantTemporalAxes } from "@local/hash-isomorphic-utils/graph-queries"; import { blockProtocolEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { generateTypeId } from "@local/hash-isomorphic-utils/ontology-types"; @@ -113,16 +110,13 @@ export const createEntityType: ImpureGraphFunction< const { graphApi } = ctx; - const { data: metadata } = await graphApi.createEntityType( - authentication.actorId, - { - schema, - provenance: { - ...ctx.provenance, - ...params.provenance, - }, + const { data: metadata } = await graphApi.createEntityType(authentication.actorId, { + schema, + provenance: { + ...ctx.provenance, + ...params.provenance, }, - ); + }); // TODO: Avoid casting through `unknown` when new codegen is in place // see https://linear.app/hash/issue/H-4463/utilize-new-codegen-and-replace-custom-defined-node-types @@ -222,9 +216,7 @@ export const updateEntityTypes: ImpureGraphFunction< const input = entityTypeUpdates[index]; if (!input) { - throw new Error( - `Entity type update metadata index ${index} not present in input array`, - ); + throw new Error(`Entity type update metadata index ${index} not present in input array`); } return { @@ -252,24 +244,16 @@ export const isEntityTypeLinkEntityType: ImpureGraphFunction< > = async (context, authentication, params) => { const { allOf } = params; - if ( - allOf?.some( - ({ $ref }) => $ref === blockProtocolEntityTypes.link.entityTypeId, - ) - ) { + if (allOf?.some(({ $ref }) => $ref === blockProtocolEntityTypes.link.entityTypeId)) { return true; } const parentTypes = await Promise.all( (allOf ?? []).map(async ({ $ref }) => { - const parentEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId: $ref, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const parentEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId: $ref, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (!parentEntityType) { throw new NotFoundError(`Could not find entity type with ID ${$ref}`); } @@ -279,14 +263,12 @@ export const isEntityTypeLinkEntityType: ImpureGraphFunction< return new Promise((resolve) => { const promises = parentTypes.map((parent) => - isEntityTypeLinkEntityType(context, authentication, parent.schema).then( - (isLinkType) => { - if (isLinkType) { - // Resolve as soon as we have encountered a link type, instead of waiting for all parent types to be checked - resolve(true); - } - }, - ), + isEntityTypeLinkEntityType(context, authentication, parent.schema).then((isLinkType) => { + if (isLinkType) { + // Resolve as soon as we have encountered a link type, instead of waiting for all parent types to be checked + resolve(true); + } + }), ); void Promise.all(promises).then(() => @@ -306,10 +288,7 @@ export const archiveEntityType: ImpureGraphFunction< ArchiveEntityTypeParams, Promise > = async ({ graphApi }, { actorId }, params) => { - const { data: temporalMetadata } = await graphApi.archiveEntityType( - actorId, - params, - ); + const { data: temporalMetadata } = await graphApi.archiveEntityType(actorId, params); return temporalMetadata as OntologyTemporalMetadata; }; @@ -324,10 +303,10 @@ export const unarchiveEntityType: ImpureGraphFunction< Omit, Promise > = async ({ graphApi, provenance }, { actorId }, params) => { - const { data: temporalMetadata } = await graphApi.unarchiveEntityType( - actorId, - { ...params, provenance }, - ); + const { data: temporalMetadata } = await graphApi.unarchiveEntityType(actorId, { + ...params, + provenance, + }); return temporalMetadata as OntologyTemporalMetadata; }; diff --git a/apps/hash-api/src/graph/ontology/primitive/property-type.ts b/apps/hash-api/src/graph/ontology/primitive/property-type.ts index 7a33c815b3b..402f1d86f80 100644 --- a/apps/hash-api/src/graph/ontology/primitive/property-type.ts +++ b/apps/hash-api/src/graph/ontology/primitive/property-type.ts @@ -37,10 +37,7 @@ export const createPropertyType: ImpureGraphFunction< webId: WebId; schema: ConstructPropertyTypeParams; webShortname?: string; - provenance?: Omit< - ProvidedOntologyEditionProvenance, - "origin" | "actorType" - >; + provenance?: Omit; }, Promise > = async (ctx, authentication, params) => { @@ -67,16 +64,13 @@ export const createPropertyType: ImpureGraphFunction< const { graphApi } = ctx; - const { data: metadata } = await graphApi.createPropertyType( - authentication.actorId, - { - schema, - provenance: { - ...ctx.provenance, - ...params.provenance, - }, + const { data: metadata } = await graphApi.createPropertyType(authentication.actorId, { + schema, + provenance: { + ...ctx.provenance, + ...params.provenance, }, - ); + }); // TODO: Avoid casting through `unknown` when new codegen is in place // see https://linear.app/hash/issue/H-4463/utilize-new-codegen-and-replace-custom-defined-node-types @@ -112,10 +106,7 @@ export const updatePropertyType: ImpureGraphFunction< }, }; - const { data: metadata } = await ctx.graphApi.updatePropertyType( - actorId, - updateArguments, - ); + const { data: metadata } = await ctx.graphApi.updatePropertyType(actorId, updateArguments); const { recordId } = metadata; @@ -146,10 +137,7 @@ export const archivePropertyType: ImpureGraphFunction< ArchivePropertyTypeParams, Promise > = async ({ graphApi }, { actorId }, params) => { - const { data: temporalMetadata } = await graphApi.archivePropertyType( - actorId, - params, - ); + const { data: temporalMetadata } = await graphApi.archivePropertyType(actorId, params); return temporalMetadata as OntologyTemporalMetadata; }; @@ -164,10 +152,10 @@ export const unarchivePropertyType: ImpureGraphFunction< Omit, Promise > = async ({ graphApi, provenance }, { actorId }, params) => { - const { data: temporalMetadata } = await graphApi.unarchivePropertyType( - actorId, - { ...params, provenance }, - ); + const { data: temporalMetadata } = await graphApi.unarchivePropertyType(actorId, { + ...params, + provenance, + }); return temporalMetadata as OntologyTemporalMetadata; }; diff --git a/apps/hash-api/src/graph/ontology/primitive/util.ts b/apps/hash-api/src/graph/ontology/primitive/util.ts index 913ebe2d7a8..518877f5fc6 100644 --- a/apps/hash-api/src/graph/ontology/primitive/util.ts +++ b/apps/hash-api/src/graph/ontology/primitive/util.ts @@ -18,18 +18,12 @@ export const getWebShortname: ImpureGraphFunction< }, Promise > = (ctx, authentication, params) => - getWebById(ctx.graphApi, authentication, params.accountOrAccountGroupId).then( - (web) => { - if (!web) { - throw new Error( - `failed to get web for id: ${params.accountOrAccountGroupId}`, - ); - } - if (!web.shortname) { - throw new Error( - `Shortname is not set for web: ${params.accountOrAccountGroupId}`, - ); - } - return web.shortname; - }, - ); + getWebById(ctx.graphApi, authentication, params.accountOrAccountGroupId).then((web) => { + if (!web) { + throw new Error(`failed to get web for id: ${params.accountOrAccountGroupId}`); + } + if (!web.shortname) { + throw new Error(`Shortname is not set for web: ${params.accountOrAccountGroupId}`); + } + return web.shortname; + }); diff --git a/apps/hash-api/src/graphql/create-apollo-server.ts b/apps/hash-api/src/graphql/create-apollo-server.ts index dbef03b36ac..eec1e21b6bf 100644 --- a/apps/hash-api/src/graphql/create-apollo-server.ts +++ b/apps/hash-api/src/graphql/create-apollo-server.ts @@ -32,11 +32,7 @@ import type { StatsD } from "hot-shots"; import type Keyv from "keyv"; import type { Server } from "node:http"; -const statsPlugin = ({ - statsd, -}: { - statsd?: StatsD; -}): ApolloServerPlugin => ({ +const statsPlugin = ({ statsd }: { statsd?: StatsD }): ApolloServerPlugin => ({ requestDidStart: async () => { const startTimestamp = performance.now(); @@ -84,9 +80,7 @@ const statsPlugin = ({ const elapsed = performance.now() - startTimestamp; // take the first part of the UA to help identify browser vs server requests - const userAgent = ctx.request.http?.headers - .get("user-agent") - ?.split(" ")[0]; + const userAgent = ctx.request.http?.headers.get("user-agent")?.split(" ")[0]; const msg = { operation: ctx.operationName, diff --git a/apps/hash-api/src/graphql/error.ts b/apps/hash-api/src/graphql/error.ts index 992a57ac783..724c8d52d1a 100644 --- a/apps/hash-api/src/graphql/error.ts +++ b/apps/hash-api/src/graphql/error.ts @@ -8,31 +8,17 @@ export const code = ( extensions?: Record, ) => new GraphQLError(message, { extensions: { code, ...extensions } }); -export const badUserInput = ( - message: string, - extensions?: Record, -) => code(ApolloServerErrorCode.BAD_USER_INPUT, message, extensions); -export const forbidden = ( - message: string, - extensions?: Record, -) => code("FORBIDDEN", message, extensions); -export const notFound = ( - message: string, - extensions?: Record, -) => code("NOT_FOUND", message, extensions); -export const cyclicTree = ( - message: string, - extensions?: Record, -) => code("CYCLIC_TREE", message, extensions); -export const badRequest = ( - message: string, - extensions?: Record, -) => code(ApolloServerErrorCode.BAD_REQUEST, message, extensions); -export const invalidInvitationType = ( - message: string, - extensions?: Record, -) => code("INVALID_INVITATION_TYPE", message, extensions); -export const internal = ( - message: string, - extensions?: Record, -) => code(ApolloServerErrorCode.INTERNAL_SERVER_ERROR, message, extensions); +export const badUserInput = (message: string, extensions?: Record) => + code(ApolloServerErrorCode.BAD_USER_INPUT, message, extensions); +export const forbidden = (message: string, extensions?: Record) => + code("FORBIDDEN", message, extensions); +export const notFound = (message: string, extensions?: Record) => + code("NOT_FOUND", message, extensions); +export const cyclicTree = (message: string, extensions?: Record) => + code("CYCLIC_TREE", message, extensions); +export const badRequest = (message: string, extensions?: Record) => + code(ApolloServerErrorCode.BAD_REQUEST, message, extensions); +export const invalidInvitationType = (message: string, extensions?: Record) => + code("INVALID_INVITATION_TYPE", message, extensions); +export const internal = (message: string, extensions?: Record) => + code(ApolloServerErrorCode.INTERNAL_SERVER_ERROR, message, extensions); diff --git a/apps/hash-api/src/graphql/resolvers/blockprotocol/get-block.ts b/apps/hash-api/src/graphql/resolvers/blockprotocol/get-block.ts index 384234d6eff..38ae3115a2f 100644 --- a/apps/hash-api/src/graphql/resolvers/blockprotocol/get-block.ts +++ b/apps/hash-api/src/graphql/resolvers/blockprotocol/get-block.ts @@ -22,13 +22,9 @@ export const getBlockProtocolBlocksResolver: ResolverFn< }); if (res.status === 401) { - throw Error.forbidden( - `Invalid BLOCK_PROTOCOL_API_KEY for ${blockProtocolHubOrigin}`, - ); + throw Error.forbidden(`Invalid BLOCK_PROTOCOL_API_KEY for ${blockProtocolHubOrigin}`); } else if (res.status !== 200) { - throw Error.internal( - `Could not fetch blocks from Block Protocol Hub: ${res.statusText}`, - ); + throw Error.internal(`Could not fetch blocks from Block Protocol Hub: ${res.statusText}`); } const { results } = await (res.json() as Promise<{ diff --git a/apps/hash-api/src/graphql/resolvers/embed/index.ts b/apps/hash-api/src/graphql/resolvers/embed/index.ts index 25a7508d107..45c7bd4a1d8 100644 --- a/apps/hash-api/src/graphql/resolvers/embed/index.ts +++ b/apps/hash-api/src/graphql/resolvers/embed/index.ts @@ -3,12 +3,7 @@ import sanitizeHtml from "sanitize-html"; import * as Error from "../../error"; -import type { - Embed, - Maybe, - QueryEmbedCodeArgs, - ResolverFn, -} from "../../api-types.gen"; +import type { Embed, Maybe, QueryEmbedCodeArgs, ResolverFn } from "../../api-types.gen"; import type { GraphQLContext } from "../../context"; /** @@ -71,9 +66,7 @@ const sanitizeOembedHtml = (html: string): string => "text-align": [/^(?:left|right|center|justify)$/], "vertical-align": [/^(?:top|middle|bottom|baseline)$/], display: [/^(?:block|inline|inline-block|flex|none)$/], - margin: [ - /^[\d.]+(?:px|em|rem|%|auto)(?:\s+[\d.]+(?:px|em|rem|%|auto)){0,3}$/, - ], + margin: [/^[\d.]+(?:px|em|rem|%|auto)(?:\s+[\d.]+(?:px|em|rem|%|auto)){0,3}$/], padding: [/^[\d.]+(?:px|em|rem|%)(?:\s+[\d.]+(?:px|em|rem|%)){0,3}$/], border: [/^(?:none|\d+px\s+\w+\s+#?[a-zA-Z0-9]+)$/], "aspect-ratio": [/^[\d.]+\s*\/\s*[\d.]+$/], @@ -152,13 +145,7 @@ const getOembedEndpoint = (url: string, type?: string) => { } }; -async function getEmbedResponse({ - url, - type, -}: { - url: string; - type?: Maybe; -}) { +async function getEmbedResponse({ url, type }: { url: string; type?: Maybe }) { const oembedEndpoint = getOembedEndpoint(url, type || undefined); if (!oembedEndpoint) { @@ -167,9 +154,9 @@ async function getEmbedResponse({ }; } - return await fetch( - `${oembedEndpoint}?url=${encodeURIComponent(url)}&maxwidth=1000`, - ).then((response) => response.json()); + return await fetch(`${oembedEndpoint}?url=${encodeURIComponent(url)}&maxwidth=1000`).then( + (response) => response.json(), + ); } export const embedCode: ResolverFn< @@ -183,9 +170,7 @@ export const embedCode: ResolverFn< type, }).catch((__) => { throw Error.notFound( - `Embed Code for URL ${url} not found${ - type?.trim() ? ` for type ${type}` : "" - }`, + `Embed Code for URL ${url} not found${type?.trim() ? ` for type ${type}` : ""}`, ); })) as OembedResponse & { error: boolean }; @@ -193,9 +178,7 @@ export const embedCode: ResolverFn< if (error) { throw Error.notFound( - `Embed Code for URL ${url} not found${ - type?.trim() ? ` for type ${type}` : "" - }`, + `Embed Code for URL ${url} not found${type?.trim() ? ` for type ${type}` : ""}`, ); } diff --git a/apps/hash-api/src/graphql/resolvers/flows/cancel-flow.ts b/apps/hash-api/src/graphql/resolvers/flows/cancel-flow.ts index c1792600628..cdb73a6e998 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/cancel-flow.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/cancel-flow.ts @@ -14,11 +14,7 @@ export const cancelFlow: ResolverFn< Record, LoggedInGraphQLContext, MutationResetFlowArgs -> = async ( - _, - { flowUuid }, - { authentication, dataSources, provenance, temporal, user }, -) => { +> = async (_, { flowUuid }, { authentication, dataSources, provenance, temporal, user }) => { const flow = await getFlowRunEntityById({ flowRunId: flowUuid as EntityUuid, graphApiClient: dataSources.graphApi, diff --git a/apps/hash-api/src/graphql/resolvers/flows/flow-schedule.ts b/apps/hash-api/src/graphql/resolvers/flows/flow-schedule.ts index 614791aa478..0886fde9209 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/flow-schedule.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/flow-schedule.ts @@ -52,23 +52,15 @@ export const createFlowScheduleResolver: ResolverFn< throw GraphQLError.badRequest("Data sources are required for AI flows"); } - const schedule = await createFlowScheduleEntity( - context, - authentication, - input, - ); + const schedule = await createFlowScheduleEntity(context, authentication, input); const props = simplifyProperties(schedule.properties); - const scheduleId = extractEntityUuidFromEntityId( - schedule.metadata.recordId.entityId, - ); + const scheduleId = extractEntityUuidFromEntityId(schedule.metadata.recordId.entityId); const taskQueue = flowType; const workflowParams: RunFlowWorkflowParams = { - ...(flowType === "ai" && input.dataSources - ? { dataSources: input.dataSources } - : {}), + ...(flowType === "ai" && input.dataSources ? { dataSources: input.dataSources } : {}), flowDefinition, flowRunName: input.name, flowTrigger: input.flowTrigger, @@ -104,16 +96,10 @@ export const createFlowScheduleResolver: ResolverFn< }, }); } catch (err) { - await schedule.archive( - context.graphApi, - authentication, - context.provenance, - ); + await schedule.archive(context.graphApi, authentication, context.provenance); const message = err instanceof Error ? err.message : String(err); - throw GraphQLError.internal( - `Failed to create Temporal schedule: ${message}`, - ); + throw GraphQLError.internal(`Failed to create Temporal schedule: ${message}`); } return scheduleId; @@ -136,9 +122,7 @@ export const updateFlowScheduleResolver: ResolverFn< }); // Update the Temporal schedule if relevant fields changed - const scheduleId = extractEntityUuidFromEntityId( - schedule.metadata.recordId.entityId, - ); + const scheduleId = extractEntityUuidFromEntityId(schedule.metadata.recordId.entityId); try { const handle = temporal.schedule.getHandle(scheduleId); @@ -165,9 +149,7 @@ export const updateFlowScheduleResolver: ResolverFn< ...(typeof input.catchupWindowMs === "number" ? { catchupWindow: input.catchupWindowMs } : {}), - ...(input.pauseOnFailure !== undefined - ? { pauseOnFailure: input.pauseOnFailure } - : {}), + ...(input.pauseOnFailure !== undefined ? { pauseOnFailure: input.pauseOnFailure } : {}), }, })); } @@ -177,9 +159,7 @@ export const updateFlowScheduleResolver: ResolverFn< const { dataSources } = input; await handle.update((prev) => { - const existingParams = prev.action.args?.[0] as - | RunFlowWorkflowParams - | undefined; + const existingParams = prev.action.args?.[0] as RunFlowWorkflowParams | undefined; if (!existingParams) { // This shouldn't happen for a valid existing schedule @@ -214,11 +194,9 @@ export const pauseFlowScheduleResolver: ResolverFn< const context = graphQLContextToImpureGraphContext(graphQLContext); const { authentication } = graphQLContext; - const existingSchedule = await getFlowScheduleEntityById( - context, - authentication, - { scheduleEntityId }, - ); + const existingSchedule = await getFlowScheduleEntityById(context, authentication, { + scheduleEntityId, + }); const { scheduleStatus } = simplifyProperties(existingSchedule.properties); @@ -232,9 +210,7 @@ export const pauseFlowScheduleResolver: ResolverFn< }); // Pause the Temporal schedule - const scheduleId = extractEntityUuidFromEntityId( - schedule.metadata.recordId.entityId, - ); + const scheduleId = extractEntityUuidFromEntityId(schedule.metadata.recordId.entityId); try { const handle = temporal.schedule.getHandle(scheduleId); @@ -262,15 +238,11 @@ export const resumeFlowScheduleResolver: ResolverFn< const context = graphQLContextToImpureGraphContext(graphQLContext); const { authentication } = graphQLContext; - const existingSchedule = await getFlowScheduleEntityById( - context, - authentication, - { scheduleEntityId }, - ); + const existingSchedule = await getFlowScheduleEntityById(context, authentication, { + scheduleEntityId, + }); - const { scheduleStatus, schedulePauseState } = simplifyProperties( - existingSchedule.properties, - ); + const { scheduleStatus, schedulePauseState } = simplifyProperties(existingSchedule.properties); if (scheduleStatus === "active") { return true; @@ -282,9 +254,7 @@ export const resumeFlowScheduleResolver: ResolverFn< }); // Resume the Temporal schedule - const scheduleId = extractEntityUuidFromEntityId( - schedule.metadata.recordId.entityId, - ); + const scheduleId = extractEntityUuidFromEntityId(schedule.metadata.recordId.entityId); try { const handle = temporal.schedule.getHandle(scheduleId); @@ -318,9 +288,7 @@ export const archiveFlowScheduleResolver: ResolverFn< scheduleEntityId, }); - const scheduleId = extractEntityUuidFromEntityId( - schedule.metadata.recordId.entityId, - ); + const scheduleId = extractEntityUuidFromEntityId(schedule.metadata.recordId.entityId); await schedule.archive(context.graphApi, authentication, context.provenance); @@ -329,11 +297,7 @@ export const archiveFlowScheduleResolver: ResolverFn< await handle.delete(); } catch (err) { if (!(err instanceof ScheduleNotFoundError)) { - await schedule.unarchive( - context.graphApi, - authentication, - context.provenance, - ); + await schedule.unarchive(context.graphApi, authentication, context.provenance); throw GraphQLError.internal( `Failed to delete Temporal schedule for schedule entity ${scheduleEntityId}: ${err instanceof Error ? err.message : String(err)}`, diff --git a/apps/hash-api/src/graphql/resolvers/flows/get-flow-run-by-id.ts b/apps/hash-api/src/graphql/resolvers/flows/get-flow-run-by-id.ts index 0e647e13cbd..e3d12fe628b 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/get-flow-run-by-id.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/get-flow-run-by-id.ts @@ -3,11 +3,7 @@ import { getFlowRunById } from "@local/hash-backend-utils/flows"; import * as Error from "../../error"; import { wereDetailedFieldsRequested } from "./shared/were-detailed-fields-requested"; -import type { - FlowRun, - QueryGetFlowRunByIdArgs, - ResolverFn, -} from "../../api-types.gen"; +import type { FlowRun, QueryGetFlowRunByIdArgs, 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"; diff --git a/apps/hash-api/src/graphql/resolvers/flows/get-flow-runs.ts b/apps/hash-api/src/graphql/resolvers/flows/get-flow-runs.ts index 8d27ac2f0e2..70ddc07ebed 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/get-flow-runs.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/get-flow-runs.ts @@ -2,11 +2,7 @@ import { getFlowRuns } from "@local/hash-backend-utils/flows"; import { wereDetailedFieldsRequested } from "./shared/were-detailed-fields-requested"; -import type { - FlowRun, - QueryGetFlowRunsArgs, - ResolverFn, -} from "../../api-types.gen"; +import type { FlowRun, QueryGetFlowRunsArgs, ResolverFn } from "../../api-types.gen"; import type { GraphQLContext } from "../../context"; import type { SparseFlowRun } from "@local/hash-isomorphic-utils/flows/types"; diff --git a/apps/hash-api/src/graphql/resolvers/flows/reset-flow.ts b/apps/hash-api/src/graphql/resolvers/flows/reset-flow.ts index f5811ba8003..502448a139a 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/reset-flow.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/reset-flow.ts @@ -54,8 +54,7 @@ export const resetFlow: ResolverFn< * If we don't set this, Temporal will replay signals sent after the cancellation point to the new workflow execution. * Instead, we just want the events for any signals sent _prior_ to the cancellation point in the history. */ - resetReapplyType: - proto.temporal.api.enums.v1.ResetReapplyType.RESET_REAPPLY_TYPE_NONE, + resetReapplyType: proto.temporal.api.enums.v1.ResetReapplyType.RESET_REAPPLY_TYPE_NONE, reason: checkpointId, requestId: generateUuid(), workflowTaskFinishEventId: Long.fromInt(eventId), diff --git a/apps/hash-api/src/graphql/resolvers/flows/shared/were-detailed-fields-requested.ts b/apps/hash-api/src/graphql/resolvers/flows/shared/were-detailed-fields-requested.ts index 7876e1d4a40..3441f8698d3 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/shared/were-detailed-fields-requested.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/shared/were-detailed-fields-requested.ts @@ -10,16 +10,15 @@ import type { ResolveTree } from "graphql-parse-resolve-info"; * Works for both `getFlowRuns` (returns `PaginatedFlowRuns` wrapping `FlowRun`) * and `getFlowRunById` (returns `FlowRun` directly). */ -export const wereDetailedFieldsRequested = ( - info: GraphQLResolveInfo, -): boolean => { +export const wereDetailedFieldsRequested = (info: GraphQLResolveInfo): boolean => { const parsedResolveInfoFragment = parseResolveInfo(info); let requestedFieldsTree = parsedResolveInfoFragment?.fieldsByTypeName.FlowRun; if (!requestedFieldsTree) { - const paginatedFields = parsedResolveInfoFragment?.fieldsByTypeName - .PaginatedFlowRuns as Record | undefined; + const paginatedFields = parsedResolveInfoFragment?.fieldsByTypeName.PaginatedFlowRuns as + | Record + | undefined; requestedFieldsTree = paginatedFields?.flowRuns?.fieldsByTypeName.FlowRun; } diff --git a/apps/hash-api/src/graphql/resolvers/flows/start-flow.ts b/apps/hash-api/src/graphql/resolvers/flows/start-flow.ts index 492619419c8..06a80f8767f 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/start-flow.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/start-flow.ts @@ -1,10 +1,7 @@ import { validateFlowDefinition } from "@local/hash-isomorphic-utils/flows/util"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; -import { - type MutationStartFlowArgs, - type ResolverFn, -} from "../../api-types.gen"; +import { type MutationStartFlowArgs, type ResolverFn } from "../../api-types.gen"; import * as Error from "../../error"; import type { LoggedInGraphQLContext } from "../../context"; @@ -19,11 +16,7 @@ export const startFlow: ResolverFn< Record, LoggedInGraphQLContext, MutationStartFlowArgs -> = async ( - _, - { dataSources, flowTrigger, flowDefinition, flowType, webId }, - graphQLContext, -) => { +> = async (_, { dataSources, flowTrigger, flowDefinition, flowType, webId }, graphQLContext) => { const { temporal, user } = graphQLContext; if (flowType === "ai" && !user.enabledFeatureFlags.includes("ai")) { diff --git a/apps/hash-api/src/graphql/resolvers/flows/submit-external-input-response.ts b/apps/hash-api/src/graphql/resolvers/flows/submit-external-input-response.ts index 91ddb0ed5f6..6c113a6290a 100644 --- a/apps/hash-api/src/graphql/resolvers/flows/submit-external-input-response.ts +++ b/apps/hash-api/src/graphql/resolvers/flows/submit-external-input-response.ts @@ -3,10 +3,7 @@ import { externalInputResponseSignal } from "@local/hash-isomorphic-utils/flows/ import * as Error from "../../error"; -import type { - MutationSubmitExternalInputResponseArgs, - ResolverFn, -} from "../../api-types.gen"; +import type { MutationSubmitExternalInputResponseArgs, ResolverFn } from "../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../context"; import type { EntityUuid } from "@blockprotocol/type-system"; @@ -15,11 +12,7 @@ export const submitExternalInputResponse: ResolverFn< Record, LoggedInGraphQLContext, MutationSubmitExternalInputResponseArgs -> = async ( - _, - { response, flowUuid }, - { authentication, dataSources, temporal }, -) => { +> = async (_, { response, flowUuid }, { authentication, dataSources, temporal }) => { const flow = await getFlowRunEntityById({ flowRunId: flowUuid as EntityUuid, graphApiClient: dataSources.graphApi, diff --git a/apps/hash-api/src/graphql/resolvers/generation/generate-inverse.ts b/apps/hash-api/src/graphql/resolvers/generation/generate-inverse.ts index a149809841a..d501a0cf38d 100644 --- a/apps/hash-api/src/graphql/resolvers/generation/generate-inverse.ts +++ b/apps/hash-api/src/graphql/resolvers/generation/generate-inverse.ts @@ -84,8 +84,6 @@ export const generateInverseResolver: ResolverFn< relationship, error, }); - throw Error.internal( - `Failed to generate inverse relationship for ${relationship}`, - ); + throw Error.internal(`Failed to generate inverse relationship for ${relationship}`); } }; diff --git a/apps/hash-api/src/graphql/resolvers/generation/is-generation-available.ts b/apps/hash-api/src/graphql/resolvers/generation/is-generation-available.ts index 2b6f441d59a..8a92155ecf3 100644 --- a/apps/hash-api/src/graphql/resolvers/generation/is-generation-available.ts +++ b/apps/hash-api/src/graphql/resolvers/generation/is-generation-available.ts @@ -1,9 +1,6 @@ import { getOpenAiClient } from "./shared/openai-client"; -import type { - IsGenerationAvailableResponse, - ResolverFn, -} from "../../api-types.gen"; +import type { IsGenerationAvailableResponse, ResolverFn } from "../../api-types.gen"; import type { GraphQLContext } from "../../context"; import type OpenAI from "openai"; diff --git a/apps/hash-api/src/graphql/resolvers/index.ts b/apps/hash-api/src/graphql/resolvers/index.ts index 1dbfa76322a..ab2b520bbbe 100644 --- a/apps/hash-api/src/graphql/resolvers/index.ts +++ b/apps/hash-api/src/graphql/resolvers/index.ts @@ -59,16 +59,10 @@ import { getPendingInvitationByEntityIdResolver } from "./knowledge/org/get-pend import { inviteUserToOrgResolver } from "./knowledge/org/invite-user-to-org"; import { removeUserFromOrgResolver } from "./knowledge/org/remove-user-from-org"; import { pageContents } from "./knowledge/page"; -import { - createPageResolver, - pageCommentsResolver, -} from "./knowledge/page/page"; +import { createPageResolver, pageCommentsResolver } from "./knowledge/page/page"; import { setParentPageResolver } from "./knowledge/page/set-parent-page"; import { updatePageResolver } from "./knowledge/page/update-page"; -import { - canUserEdit, - checkUserPermissionsOnEntity, -} from "./knowledge/shared/check-permissions"; +import { canUserEdit, checkUserPermissionsOnEntity } from "./knowledge/shared/check-permissions"; import { getUsageRecordsResolver } from "./knowledge/user/get-usage-records"; import { getWaitlistPositionResolver } from "./knowledge/user/get-waitlist-position"; import { hasAccessToHashResolver } from "./knowledge/user/has-access-to-hash"; @@ -142,9 +136,7 @@ export const resolvers: Omit & { getWaitlistPosition: loggedInMiddleware(getWaitlistPositionResolver), /** Logged in and signed up users */ - getBlockProtocolBlocks: loggedInAndSignedUpMiddleware( - getBlockProtocolBlocksResolver, - ), + getBlockProtocolBlocks: loggedInAndSignedUpMiddleware(getBlockProtocolBlocksResolver), getUsageRecords: loggedInAndSignedUpMiddleware(getUsageRecordsResolver), pageComments: loggedInAndSignedUpMiddleware(pageCommentsResolver), blocks: loggedInAndSignedUpMiddleware(blocksResolver), @@ -153,22 +145,14 @@ export const resolvers: Omit & { getFlowRunById: loggedInAndSignedUpMiddleware(getFlowRunByIdResolver), isEntityPublic: loggedInAndSignedUpMiddleware(isEntityPublicResolver), getEntityAuthorizationRelationships: loggedInAndSignedUpMiddleware(() => { - throw new Error( - "`getEntityAuthorizationRelationships` is not implemented", - ); + throw new Error("`getEntityAuthorizationRelationships` is not implemented"); }), countEntities: loggedInAndSignedUpMiddleware(countEntitiesResolver), queryEntities: loggedInAndSignedUpMiddleware(queryEntitiesResolver), - queryEntitySubgraph: loggedInAndSignedUpMiddleware( - queryEntitySubgraphResolver, - ), - getMyPendingInvitations: loggedInAndSignedUpMiddleware( - getMyPendingInvitationsResolver, - ), + queryEntitySubgraph: loggedInAndSignedUpMiddleware(queryEntitySubgraphResolver), + getMyPendingInvitations: loggedInAndSignedUpMiddleware(getMyPendingInvitationsResolver), - getLinearOrganization: loggedInAndSignedUpMiddleware( - getLinearOrganizationResolver, - ), + getLinearOrganization: loggedInAndSignedUpMiddleware(getLinearOrganizationResolver), checkUserPermissionsOnEntity: (_, { metadata }, context, info) => checkUserPermissionsOnEntity({ metadata }, _, context, info), checkUserPermissionsOnEntityType: loggedInAndSignedUpMiddleware( @@ -191,25 +175,15 @@ export const resolvers: Omit & { updateEntity: loggedInMiddleware(updateEntityResolver), /** Logged in and signed up users */ - updateBlockCollectionContents: loggedInAndSignedUpMiddleware( - updateBlockCollectionContents, - ), + updateBlockCollectionContents: loggedInAndSignedUpMiddleware(updateBlockCollectionContents), requestFileUpload: loggedInAndSignedUpMiddleware(requestFileUpload), createFileFromUrl: loggedInAndSignedUpMiddleware(createFileFromUrl), // Ontology - createPropertyType: loggedInAndSignedUpMiddleware( - createPropertyTypeResolver, - ), - updatePropertyType: loggedInAndSignedUpMiddleware( - updatePropertyTypeResolver, - ), - archivePropertyType: loggedInAndSignedUpMiddleware( - archivePropertyTypeResolver, - ), - unarchivePropertyType: loggedInAndSignedUpMiddleware( - unarchivePropertyTypeResolver, - ), + createPropertyType: loggedInAndSignedUpMiddleware(createPropertyTypeResolver), + updatePropertyType: loggedInAndSignedUpMiddleware(updatePropertyTypeResolver), + archivePropertyType: loggedInAndSignedUpMiddleware(archivePropertyTypeResolver), + unarchivePropertyType: loggedInAndSignedUpMiddleware(unarchivePropertyTypeResolver), createDataType: loggedInAndSignedUpMiddleware(createDataTypeResolver), updateDataType: loggedInAndSignedUpMiddleware(updateDataTypeResolver), archiveDataType: loggedInAndSignedUpMiddleware(archiveDataTypeResolver), @@ -218,9 +192,7 @@ export const resolvers: Omit & { updateEntityType: loggedInAndSignedUpMiddleware(updateEntityTypeResolver), updateEntityTypes: loggedInAndSignedUpMiddleware(updateEntityTypesResolver), archiveEntityType: loggedInAndSignedUpMiddleware(archiveEntityTypeResolver), - unarchiveEntityType: loggedInAndSignedUpMiddleware( - unarchiveEntityTypeResolver, - ), + unarchiveEntityType: loggedInAndSignedUpMiddleware(unarchiveEntityTypeResolver), // Knowledge createEntity: loggedInAndSignedUpMiddleware(createEntityResolver), @@ -237,12 +209,8 @@ export const resolvers: Omit & { createOrg: loggedInAndSignedUpMiddleware(createOrgResolver), inviteUserToOrg: loggedInAndSignedUpMiddleware(inviteUserToOrgResolver), - acceptOrgInvitation: loggedInAndSignedUpMiddleware( - acceptOrgInvitationResolver, - ), - declineOrgInvitation: loggedInAndSignedUpMiddleware( - declineOrgInvitationResolver, - ), + acceptOrgInvitation: loggedInAndSignedUpMiddleware(acceptOrgInvitationResolver), + declineOrgInvitation: loggedInAndSignedUpMiddleware(declineOrgInvitationResolver), removeUserFromOrg: loggedInAndSignedUpMiddleware(removeUserFromOrgResolver), addEntityOwner: loggedInAndSignedUpMiddleware(() => { @@ -258,30 +226,18 @@ export const resolvers: Omit & { throw new Error("`removeEntityEditor` is not implemented"); }), addEntityViewer: loggedInAndSignedUpMiddleware(addEntityViewerResolver), - removeEntityViewer: loggedInAndSignedUpMiddleware( - removeEntityViewerResolver, - ), + removeEntityViewer: loggedInAndSignedUpMiddleware(removeEntityViewerResolver), cancelFlow: loggedInAndSignedUpMiddleware(cancelFlow), resetFlow: loggedInAndSignedUpMiddleware(resetFlow), startFlow: loggedInAndSignedUpMiddleware(startFlow), - submitExternalInputResponse: loggedInAndSignedUpMiddleware( - submitExternalInputResponse, - ), + submitExternalInputResponse: loggedInAndSignedUpMiddleware(submitExternalInputResponse), - createFlowSchedule: loggedInAndSignedUpMiddleware( - createFlowScheduleResolver, - ), - updateFlowSchedule: loggedInAndSignedUpMiddleware( - updateFlowScheduleResolver, - ), + createFlowSchedule: loggedInAndSignedUpMiddleware(createFlowScheduleResolver), + updateFlowSchedule: loggedInAndSignedUpMiddleware(updateFlowScheduleResolver), pauseFlowSchedule: loggedInAndSignedUpMiddleware(pauseFlowScheduleResolver), - resumeFlowSchedule: loggedInAndSignedUpMiddleware( - resumeFlowScheduleResolver, - ), - archiveFlowSchedule: loggedInAndSignedUpMiddleware( - archiveFlowScheduleResolver, - ), + resumeFlowSchedule: loggedInAndSignedUpMiddleware(resumeFlowScheduleResolver), + archiveFlowSchedule: loggedInAndSignedUpMiddleware(archiveFlowScheduleResolver), // Integration syncLinearIntegrationWithWebs: loggedInAndSignedUpMiddleware( diff --git a/apps/hash-api/src/graphql/resolvers/integrations/linear/linear-organization.ts b/apps/hash-api/src/graphql/resolvers/integrations/linear/linear-organization.ts index 2d6f0d6bd63..1d201859ddb 100644 --- a/apps/hash-api/src/graphql/resolvers/integrations/linear/linear-organization.ts +++ b/apps/hash-api/src/graphql/resolvers/integrations/linear/linear-organization.ts @@ -46,15 +46,13 @@ export const getLinearOrganizationResolver: ResolverFn< id: organization.id, logoUrl: organization.logoUrl, name: organization.name, - teams: teams.map( - ({ id, name, description, color, icon, private: _private }) => ({ - id, - name, - description, - color, - icon, - private: _private, - }), - ), + teams: teams.map(({ id, name, description, color, icon, private: _private }) => ({ + id, + name, + description, + color, + icon, + private: _private, + })), }; }; diff --git a/apps/hash-api/src/graphql/resolvers/integrations/linear/sync-linear-integration-with-webs.ts b/apps/hash-api/src/graphql/resolvers/integrations/linear/sync-linear-integration-with-webs.ts index e80fa40c843..5351377156d 100644 --- a/apps/hash-api/src/graphql/resolvers/integrations/linear/sync-linear-integration-with-webs.ts +++ b/apps/hash-api/src/graphql/resolvers/integrations/linear/sync-linear-integration-with-webs.ts @@ -17,16 +17,9 @@ import { getLinearUserSecretByLinearOrgId } from "../../../../graph/knowledge/sy import { Linear } from "../../../../integrations/linear"; import { graphQLContextToImpureGraphContext } from "../../util"; -import type { - MutationSyncLinearIntegrationWithWebsArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationSyncLinearIntegrationWithWebsArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; -import type { - ActorEntityUuid, - Entity, - WebId, -} from "@blockprotocol/type-system"; +import type { ActorEntityUuid, Entity, WebId } from "@blockprotocol/type-system"; export const syncLinearIntegrationWithWebsMutation: ResolverFn< Promise, @@ -42,13 +35,9 @@ export const syncLinearIntegrationWithWebsMutation: ResolverFn< const impureGraphContext = graphQLContextToImpureGraphContext(graphQLContext); - const linearIntegration = await getLinearIntegrationById( - impureGraphContext, - authentication, - { - entityId: linearIntegrationEntityId, - }, - ); + const linearIntegration = await getLinearIntegrationById(impureGraphContext, authentication, { + entityId: linearIntegrationEntityId, + }); const userAccountId = extractWebIdFromEntityId( linearIntegration.entity.metadata.recordId.entityId, @@ -85,44 +74,31 @@ export const syncLinearIntegrationWithWebsMutation: ResolverFn< const duplicateWorkspaceSyncsToRemove = existingSyncedWebs.filter( ({ webEntity }) => - !syncWithWebs.some( - ({ webEntityId }) => - webEntity.metadata.recordId.entityId === webEntityId, - ), + !syncWithWebs.some(({ webEntityId }) => webEntity.metadata.recordId.entityId === webEntityId), ); - const linearBotAccountId = await getMachineIdByIdentifier( - impureGraphContext, - authentication, - { identifier: "linear" }, - ); + const linearBotAccountId = await getMachineIdByIdentifier(impureGraphContext, authentication, { + identifier: "linear", + }); if (!linearBotAccountId) { throw new NotFoundError("Failed to get linear bot"); } await Promise.all([ - ...duplicateWorkspaceSyncsToRemove.map( - async ({ syncLinearDataWithLinkEntity, webEntity }) => { - if ( - webEntity.metadata.entityTypeIds.includes( - systemEntityTypes.organization.entityTypeId, - ) - ) { - /** @todo: remove system account id as account group member if there are no other integrations */ - } - - return syncLinearDataWithLinkEntity.archive( - impureGraphContext.graphApi, - authentication, - provenance, - ); - }, - ), + ...duplicateWorkspaceSyncsToRemove.map(async ({ syncLinearDataWithLinkEntity, webEntity }) => { + if (webEntity.metadata.entityTypeIds.includes(systemEntityTypes.organization.entityTypeId)) { + /** @todo: remove system account id as account group member if there are no other integrations */ + } + + return syncLinearDataWithLinkEntity.archive( + impureGraphContext.graphApi, + authentication, + provenance, + ); + }), ...syncWithWebs.map(async ({ webEntityId, linearTeamIds }) => { - const webId = extractEntityUuidFromEntityId( - webEntityId, - ) as string as WebId; + const webId = extractEntityUuidFromEntityId(webEntityId) as string as WebId; const userOrOrganizationEntity = await getLatestEntityById( impureGraphContext, diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/block-collection-contents.ts b/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/block-collection-contents.ts index 7550d253a64..ef309bb44f9 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/block-collection-contents.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/block-collection-contents.ts @@ -12,9 +12,7 @@ import type { HasIndexedContent } from "@local/hash-isomorphic-utils/system-type export const blockCollectionContents: ResolverFn< { - linkEntity: HashLinkEntity< - HasSpatiallyPositionedContent | HasIndexedContent - >; + linkEntity: HashLinkEntity; rightEntity: UnresolvedBlockGQL; }[], Entity, @@ -23,14 +21,10 @@ export const blockCollectionContents: ResolverFn< > = async (blockCollection, _, graphQLContext) => { const context = graphQLContextToImpureGraphContext(graphQLContext); - const contentItems = await getBlockCollectionBlocks( - context, - graphQLContext.authentication, - { - blockCollectionEntityId: blockCollection.metadata.recordId.entityId, - blockCollectionEntityTypeIds: blockCollection.metadata.entityTypeIds, - }, - ); + const contentItems = await getBlockCollectionBlocks(context, graphQLContext.authentication, { + blockCollectionEntityId: blockCollection.metadata.recordId.entityId, + blockCollectionEntityTypeIds: blockCollection.metadata.entityTypeIds, + }); return contentItems.map(({ linkEntity, rightEntity }) => ({ linkEntity, diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-actions.ts b/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-actions.ts index c248436d8db..0288a04ad0a 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-actions.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-actions.ts @@ -47,9 +47,7 @@ export const createEntityWithPlaceholdersFn = async (originalDefinition: EntityDefinition, webId: WebId) => { const entityDefinition = produce(originalDefinition, (draft) => { if (draft.existingEntityId) { - draft.existingEntityId = placeholderResults.get( - draft.existingEntityId, - ) as EntityId; + draft.existingEntityId = placeholderResults.get(draft.existingEntityId) as EntityId; } }); @@ -59,9 +57,7 @@ export const createEntityWithPlaceholdersFn = entityId: entityDefinition.existingEntityId, }); } catch { - throw Error.notFound( - `Entity ${entityDefinition.existingEntityId} not found`, - ); + throw Error.notFound(`Entity ${entityDefinition.existingEntityId} not found`); } } else { if (!entityDefinition.entityTypeIds?.[0]) { @@ -72,10 +68,7 @@ export const createEntityWithPlaceholdersFn = return await createEntityWithLinks(context, authentication, { webId, - entityTypeIds: entityDefinition.entityTypeIds as [ - VersionedUrl, - ...VersionedUrl[], - ], + entityTypeIds: entityDefinition.entityTypeIds as [VersionedUrl, ...VersionedUrl[]], properties: entityDefinition.entityProperties ?? { value: {} }, linkedEntities: entityDefinition.linkedEntities ?? undefined, }); @@ -95,15 +88,16 @@ export const filterForAction = ( actions: UpdateBlockCollectionAction[], key: T, ): { action: NonNullable; index: number }[] => - actions.reduce< - { action: NonNullable; index: number }[] - >((acc, current, index) => { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- @todo improve logic or types to remove this comment - if (current != null && key in current) { - acc.push({ action: current[key]!, index }); - } - return acc; - }, []); + actions.reduce<{ action: NonNullable; index: number }[]>( + (acc, current, index) => { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- @todo improve logic or types to remove this comment + if (current != null && key in current) { + acc.push({ action: current[key]!, index }); + } + return acc; + }, + [], + ); const isPlaceholderId = (value: unknown): value is `placeholder-${string}` => typeof value === "string" && value.startsWith("placeholder-"); @@ -126,10 +120,7 @@ export class PlaceholderResultsMap { return this.map.has(placeholderId); } - set( - placeholderId: string | null | undefined, - entity: { entityId: EntityId }, - ) { + set(placeholderId: string | null | undefined, entity: { entityId: EntityId }) { if (isPlaceholderId(placeholderId)) { this.map.set(placeholderId, entity.entityId); } @@ -159,18 +150,13 @@ export const handleCreateNewEntity = async (params: { }): Promise => { try { const { - createEntityAction: { - entity: entityDefinition, - webId: entityWebId, - entityPlaceholderId, - }, + createEntityAction: { entity: entityDefinition, webId: entityWebId, entityPlaceholderId }, createEntityWithPlaceholders, placeholderResults, } = params; placeholderResults.set(entityPlaceholderId, { - entityId: ( - await createEntityWithPlaceholders(entityDefinition, entityWebId) - ).metadata.recordId.entityId, + entityId: (await createEntityWithPlaceholders(entityDefinition, entityWebId)).metadata + .recordId.entityId, }); } catch (error) { if ( @@ -275,9 +261,7 @@ export const handleInsertNewBlock = async ( } throw Error.internal( - `insertBlock: Could not insert new or existing block: ${JSON.stringify( - error, - )}`, + `insertBlock: Could not insert new or existing block: ${JSON.stringify(error)}`, ); } }; @@ -310,13 +294,9 @@ export const handleSwapBlockData = async ( const { newEntityEntityId } = params.swapBlockDataAction; - const newBlockDataEntity = await getLatestEntityById( - context, - authentication, - { - entityId: newEntityEntityId, - }, - ); + const newBlockDataEntity = await getLatestEntityById(context, authentication, { + entityId: newEntityEntityId, + }); await updateBlockDataEntity(context, authentication, { block, @@ -356,9 +336,7 @@ export const handleUpdateEntity = async ( ({ op: entity.properties[key] === value ? "replace" : "add", path: [key], - property: mergePropertiesAndMetadata( - (value ?? undefined) as PropertyValue, - ), + property: mergePropertiesAndMetadata((value ?? undefined) as PropertyValue), }) satisfies PropertyPatchOperation, ), }); diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-contents.ts b/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-contents.ts index 9f850d63040..86df89f9f6d 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-contents.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/block-collection/update-block-collection-contents.ts @@ -41,11 +41,7 @@ export const updateBlockCollectionContents: ResolverFn< Record, LoggedInGraphQLContext, MutationUpdateBlockCollectionContentsArgs -> = async ( - _, - { entityId: blockCollectionEntityId, actions }, - graphQLContext, -) => { +> = async (_, { entityId: blockCollectionEntityId, actions }, graphQLContext) => { const { authentication, user } = graphQLContext; const context = graphQLContextToImpureGraphContext(graphQLContext); diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/block/block.ts b/apps/hash-api/src/graphql/resolvers/knowledge/block/block.ts index 1781a2f2b35..c3522b01b14 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/block/block.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/block/block.ts @@ -15,9 +15,7 @@ export const blocksResolver: ResolverFn< const context = graphQLContextToImpureGraphContext(graphQLContext); const blocks = await Promise.all( - params.blocks.map((entityId) => - getBlockById(context, authentication, { entityId }), - ), + params.blocks.map((entityId) => getBlockById(context, authentication, { entityId })), ); return blocks.map(({ componentId, entity }) => ({ diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/block/data-entity.ts b/apps/hash-api/src/graphql/resolvers/knowledge/block/data-entity.ts index ad62bc6f12a..d2919b2af44 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/block/data-entity.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/block/data-entity.ts @@ -1,7 +1,4 @@ -import { - getBlockById, - getBlockData, -} from "../../../../graph/knowledge/system-types/block"; +import { getBlockById, getBlockData } from "../../../../graph/knowledge/system-types/block"; import { graphQLContextToImpureGraphContext } from "../../util"; import type { ResolverFn } from "../../../api-types.gen"; @@ -22,7 +19,5 @@ export const blockChildEntityResolver: ResolverFn< entityId: metadata.recordId.entityId, }); - return getBlockData(context, authentication, { block }).then((blockData) => - blockData.toJSON(), - ); + return getBlockData(context, authentication, { block }).then((blockData) => blockData.toJSON()); }; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/comment/comment.ts b/apps/hash-api/src/graphql/resolvers/knowledge/comment/comment.ts index dac2af85ec1..7b229232dfc 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/comment/comment.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/comment/comment.ts @@ -4,10 +4,7 @@ import { createComment } from "../../../../graph/knowledge/system-types/comment" import { graphQLContextToImpureGraphContext } from "../../util"; import { mapCommentToGQL } from "../graphql-mapping"; -import type { - MutationCreateCommentArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationCreateCommentArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { UnresolvedCommentGQL } from "../graphql-mapping"; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/comment/delete.ts b/apps/hash-api/src/graphql/resolvers/knowledge/comment/delete.ts index d0413502960..53f841ff83c 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/comment/delete.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/comment/delete.ts @@ -1,14 +1,8 @@ -import { - deleteComment, - getCommentById, -} from "../../../../graph/knowledge/system-types/comment"; +import { deleteComment, getCommentById } from "../../../../graph/knowledge/system-types/comment"; import { graphQLContextToImpureGraphContext } from "../../util"; import { mapCommentToGQL } from "../graphql-mapping"; -import type { - MutationDeleteCommentArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationDeleteCommentArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { UnresolvedCommentGQL } from "../graphql-mapping"; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/comment/resolve.ts b/apps/hash-api/src/graphql/resolvers/knowledge/comment/resolve.ts index f14b4876f80..3e0655e62ed 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/comment/resolve.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/comment/resolve.ts @@ -1,14 +1,8 @@ -import { - getCommentById, - resolveComment, -} from "../../../../graph/knowledge/system-types/comment"; +import { getCommentById, resolveComment } from "../../../../graph/knowledge/system-types/comment"; import { graphQLContextToImpureGraphContext } from "../../util"; import { mapCommentToGQL } from "../graphql-mapping"; -import type { - MutationResolveCommentArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationResolveCommentArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { UnresolvedCommentGQL } from "../graphql-mapping"; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/comment/update-text.ts b/apps/hash-api/src/graphql/resolvers/knowledge/comment/update-text.ts index 89961872a54..5288970446c 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/comment/update-text.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/comment/update-text.ts @@ -5,10 +5,7 @@ import { import { graphQLContextToImpureGraphContext } from "../../util"; import { mapCommentToGQL } from "../graphql-mapping"; -import type { - MutationUpdateCommentTextArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationUpdateCommentTextArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { UnresolvedCommentGQL } from "../graphql-mapping"; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/entity/entity.ts b/apps/hash-api/src/graphql/resolvers/knowledge/entity/entity.ts index a9c43736b1b..5a89fe42673 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/entity/entity.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/entity/entity.ts @@ -1,7 +1,4 @@ -import { - extractEntityUuidFromEntityId, - mustHaveAtLeastOne, -} from "@blockprotocol/type-system"; +import { extractEntityUuidFromEntityId, mustHaveAtLeastOne } from "@blockprotocol/type-system"; import { publicUserAccountId } from "@local/hash-backend-utils/public-user-account-id"; import { HashEntity, @@ -10,11 +7,7 @@ import { serializeQueryEntitiesResponse, serializeQueryEntitySubgraphResponse, } from "@local/hash-graph-sdk/entity"; -import { - createPolicy, - deletePolicyById, - queryPolicies, -} from "@local/hash-graph-sdk/policy"; +import { createPolicy, deletePolicyById, queryPolicies } from "@local/hash-graph-sdk/policy"; import { canUserReadEntity, @@ -155,14 +148,11 @@ export const updateEntityResolver: ResolverFn< const context = graphQLContextToImpureGraphContext(graphQLContext); const isIncompleteUser = !user.isAccountSignupComplete; - const isUpdatingOwnEntity = - entityId === user.entity.metadata.recordId.entityId; + const isUpdatingOwnEntity = entityId === user.entity.metadata.recordId.entityId; // The user needs to have completed signup if they aren't updating their own user entity if (isIncompleteUser && !isUpdatingOwnEntity) { - throw Error.forbidden( - "You must complete the sign-up process to perform this action.", - ); + throw Error.forbidden("You must complete the sign-up process to perform this action."); } const entity = await getLatestEntityById(context, authentication, { @@ -180,9 +170,7 @@ export const updateEntityResolver: ResolverFn< } else { updatedEntity = await updateEntity(context, authentication, { entity, - entityTypeIds: entityTypeIds - ? mustHaveAtLeastOne(entityTypeIds) - : undefined, + entityTypeIds: entityTypeIds ? mustHaveAtLeastOne(entityTypeIds) : undefined, propertyPatches, draft: draft ?? undefined, }); @@ -219,11 +207,7 @@ export const validateEntityResolver: ResolverFn< const { authentication } = graphQLContext; const context = graphQLContextToImpureGraphContext(graphQLContext); - const response = await HashEntity.validate( - context.graphApi, - authentication, - params, - ); + const response = await HashEntity.validate(context.graphApi, authentication, params); return response; }; @@ -266,11 +250,7 @@ export const archiveEntitiesResolver: ResolverFn< entityId, }); - await entity.archive( - context.graphApi, - authentication, - context.provenance, - ); + await entity.archive(context.graphApi, authentication, context.provenance); archivedEntities.push(entity); } catch { @@ -286,9 +266,7 @@ export const archiveEntitiesResolver: ResolverFn< ), ); - throw Error.internal( - `Couldn't archive entities with IDs ${entityIds.join(", ")}`, - ); + throw Error.internal(`Couldn't archive entities with IDs ${entityIds.join(", ")}`); } return true; @@ -329,9 +307,7 @@ export const removeEntityViewerResolver: ResolverFn< MutationRemoveEntityViewerArgs > = async (_, { entityId, viewer }, graphQLContext) => { if (viewer.kind !== AuthorizationSubjectKind.Public) { - throw Error.badUserInput( - "Only public viewers can be removed from an entity", - ); + throw Error.badUserInput("Only public viewers can be removed from an entity"); } const { authentication } = graphQLContext; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/file/create-file-from-url.ts b/apps/hash-api/src/graphql/resolvers/knowledge/file/create-file-from-url.ts index 2bfd2cd6caf..1f43e49ff2f 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/file/create-file-from-url.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/file/create-file-from-url.ts @@ -4,10 +4,7 @@ import { createFileFromExternalUrl } from "../../../../graph/knowledge/system-ty import { graphQLContextToImpureGraphContext } from "../../util"; import { triggerPdfAnalysisWorkflow } from "./shared"; -import type { - MutationCreateFileFromUrlArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationCreateFileFromUrlArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { Entity } from "@blockprotocol/type-system"; import type { File as FileEntity } from "@local/hash-isomorphic-utils/system-types/shared"; @@ -19,13 +16,7 @@ export const createFileFromUrl: ResolverFn< MutationCreateFileFromUrlArgs > = async ( _, - { - description, - fileEntityCreationInput, - fileEntityUpdateInput, - displayName, - url, - }, + { description, fileEntityCreationInput, fileEntityUpdateInput, displayName, url }, graphQLContext, ) => { const { authentication, temporal, user } = graphQLContext; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/file/request-file-upload.ts b/apps/hash-api/src/graphql/resolvers/knowledge/file/request-file-upload.ts index 2b22e5c48c5..db3c9c34c26 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/file/request-file-upload.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/file/request-file-upload.ts @@ -30,37 +30,24 @@ export const requestFileUpload: ResolverFn< MutationRequestFileUploadArgs > = async ( _, - { - description, - displayName, - fileEntityCreationInput, - fileEntityUpdateInput, - name, - size, - }, + { description, displayName, fileEntityCreationInput, fileEntityUpdateInput, name, size }, graphQLContext, ) => { const { authentication, temporal, user } = graphQLContext; const context = graphQLContextToImpureGraphContext(graphQLContext); if (size > maximumFileSizeInBytes) { - throw Error.badUserInput( - `The file size must be less than ${maximumFileSizeInMegaBytes} MB`, - ); + throw Error.badUserInput(`The file size must be less than ${maximumFileSizeInMegaBytes} MB`); } - const { presignedPut, entity } = await createFileFromUploadRequest( - context, - authentication, - { - description, - displayName, - fileEntityCreationInput, - fileEntityUpdateInput, - name, - size, - }, - ); + const { presignedPut, entity } = await createFileFromUploadRequest(context, authentication, { + description, + displayName, + fileEntityCreationInput, + fileEntityUpdateInput, + name, + size, + }); if (user.enabledFeatureFlags.includes("ai")) { await triggerPdfAnalysisWorkflow({ diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/file/shared.ts b/apps/hash-api/src/graphql/resolvers/knowledge/file/shared.ts index f708489e997..6c621906d7c 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/file/shared.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/file/shared.ts @@ -23,9 +23,7 @@ export const triggerPdfAnalysisWorkflow = async ({ const { entityId, properties } = entity; const mimeType = - properties[ - "https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/" - ]; + properties["https://blockprotocol.org/@blockprotocol/types/property-type/mime-type/"]; if (mimeType !== "application/pdf") { return; @@ -67,8 +65,7 @@ export const triggerPdfAnalysisWorkflow = async ({ taskQueue: "ai", args: [params], memo: { - flowDefinitionId: - inferMetadataFromDocumentFlowDefinition.flowDefinitionId, + flowDefinitionId: inferMetadataFromDocumentFlowDefinition.flowDefinitionId, userAccountId, webId, }, diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/graphql-mapping.ts b/apps/hash-api/src/graphql/resolvers/knowledge/graphql-mapping.ts index 39c471fea84..af5f2febc19 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/graphql-mapping.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/graphql-mapping.ts @@ -7,10 +7,7 @@ import type { Page as GQLPage, } from "../../api-types.gen"; -export type ExternalPageResolversGQL = - | "contents" - | "canUserEdit" - | "userPermissions"; +export type ExternalPageResolversGQL = "contents" | "canUserEdit" | "userPermissions"; export type UnresolvedPageGQL = Omit; export const mapPageToGQL = (page: Page): UnresolvedPageGQL => ({ @@ -30,10 +27,7 @@ export type ExternalCommentResolversGQL = | "parent" | "author" | "replies"; -export type UnresolvedCommentGQL = Omit< - GQLComment, - ExternalCommentResolversGQL ->; +export type UnresolvedCommentGQL = Omit; export const mapCommentToGQL = (comment: Comment): UnresolvedCommentGQL => ({ properties: comment.entity.properties, diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/org/accept-org-invitation.ts b/apps/hash-api/src/graphql/resolvers/knowledge/org/accept-org-invitation.ts index 68dcc742c6b..d067da5f336 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/org/accept-org-invitation.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/org/accept-org-invitation.ts @@ -10,10 +10,7 @@ import { getEntityIncomingLinks, getLatestEntityById, } from "../../../../graph/knowledge/primitive/entity"; -import { - getOrgById, - type Org, -} from "../../../../graph/knowledge/system-types/org"; +import { getOrgById, type Org } from "../../../../graph/knowledge/system-types/org"; import { getUserVerifiedEmails, isUserMemberOfOrg, @@ -23,10 +20,7 @@ import { systemAccountId } from "../../../../graph/system-account"; import * as Error from "../../../error"; import { graphQLContextToImpureGraphContext } from "../../util"; -import type { - AcceptInvitationResult, - ResolverFn, -} from "../../../api-types.gen"; +import type { AcceptInvitationResult, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { HashEntity } from "@local/hash-graph-sdk/entity"; import type { MutationAcceptOrgInvitationArgs } from "@local/hash-isomorphic-utils/graphql/api-types.gen"; @@ -53,13 +47,9 @@ export const acceptOrgInvitationResolver: ResolverFn< }; try { - invitation = await getLatestEntityById( - context, - systemAccountAuthentication, - { - entityId: orgInvitationEntityId, - }, - ); + invitation = await getLatestEntityById(context, systemAccountAuthentication, { + entityId: orgInvitationEntityId, + }); } catch { throw Error.notFound("Invitation not found"); } @@ -67,22 +57,16 @@ export const acceptOrgInvitationResolver: ResolverFn< let isForUser: boolean; if (isInvitationByEmail(invitation)) { - const verifiedEmails = await getUserVerifiedEmails( - context, - graphQLContext.authentication, - { - user, - }, - ); + const verifiedEmails = await getUserVerifiedEmails(context, graphQLContext.authentication, { + user, + }); isForUser = verifiedEmails.includes( invitation.properties["https://hash.ai/@h/types/property-type/email/"], ); } else if (isInvitationByShortname(invitation)) { isForUser = - invitation.properties[ - "https://hash.ai/@h/types/property-type/shortname/" - ] === user.shortname; + invitation.properties["https://hash.ai/@h/types/property-type/shortname/"] === user.shortname; } else { throw Error.invalidInvitationType( `Invalid invitation type ${invitation.metadata.entityTypeIds.join(", ")}`, @@ -112,27 +96,15 @@ export const acceptOrgInvitationResolver: ResolverFn< throw Error.notFound("Invitation link not found"); } - const isAlreadyAMember = await isUserMemberOfOrg( - context, - graphQLContext.authentication, - { - userEntityId: user.entity.metadata.recordId.entityId, - orgEntityUuid: extractWebIdFromEntityId(invitation.entityId), - }, - ); + const isAlreadyAMember = await isUserMemberOfOrg(context, graphQLContext.authentication, { + userEntityId: user.entity.metadata.recordId.entityId, + orgEntityUuid: extractWebIdFromEntityId(invitation.entityId), + }); const archiveInvitation = () => Promise.all([ - invitation.archive( - context.graphApi, - systemAccountAuthentication, - context.provenance, - ), - invitationLink.archive( - context.graphApi, - systemAccountAuthentication, - context.provenance, - ), + invitation.archive(context.graphApi, systemAccountAuthentication, context.provenance), + invitationLink.archive(context.graphApi, systemAccountAuthentication, context.provenance), ]); if (isAlreadyAMember) { @@ -158,11 +130,8 @@ export const acceptOrgInvitationResolver: ResolverFn< } if ( - new Date( - invitation.properties[ - "https://hash.ai/@h/types/property-type/expired-at/" - ], - ) < new Date() + new Date(invitation.properties["https://hash.ai/@h/types/property-type/expired-at/"]) < + new Date() ) { await archiveInvitation(); @@ -182,21 +151,15 @@ export const acceptOrgInvitationResolver: ResolverFn< * Although the creator must have been an administrator of the organization to issue the invitation, * they may have been removed as an admin since, in which case the link is no longer valid. */ - const creatorIsOrgAdmin = await getActorGroupRole( - context.graphApi, - systemAccountAuthentication, - { - actorId: linkCreator, - actorGroupId: orgWebId, - }, - ).then((role) => role === "administrator"); + const creatorIsOrgAdmin = await getActorGroupRole(context.graphApi, systemAccountAuthentication, { + actorId: linkCreator, + actorGroupId: orgWebId, + }).then((role) => role === "administrator"); if (!creatorIsOrgAdmin) { await archiveInvitation(); - throw Error.forbidden( - "Invitation issuer is not an administrator of the organization", - ); + throw Error.forbidden("Invitation issuer is not an administrator of the organization"); } const membershipCreationAuthentication = { diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/org/decline-org-invitation.ts b/apps/hash-api/src/graphql/resolvers/knowledge/org/decline-org-invitation.ts index 9cfceab9f80..ee44b632080 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/org/decline-org-invitation.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/org/decline-org-invitation.ts @@ -64,13 +64,9 @@ export const declineOrgInvitationResolver: ResolverFn< } if ("email" in invitation) { - const verifiedEmails = await getUserVerifiedEmails( - context, - graphQLContext.authentication, - { - user, - }, - ); + const verifiedEmails = await getUserVerifiedEmails(context, graphQLContext.authentication, { + user, + }); if (!verifiedEmails.includes(invitation.email)) { throw Error.notFound("Invitation for user not found"); diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/org/get-pending-invitation-by-entity-id.ts b/apps/hash-api/src/graphql/resolvers/knowledge/org/get-pending-invitation-by-entity-id.ts index f2e3dfe743d..c856aaf6b39 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/org/get-pending-invitation-by-entity-id.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/org/get-pending-invitation-by-entity-id.ts @@ -3,10 +3,7 @@ import { systemAccountId } from "../../../../graph/system-account"; import { graphQLContextToImpureGraphContext } from "../../util"; import { getPendingOrgInvitationsFromSubgraph } from "./shared"; -import type { - QueryGetPendingInvitationByEntityIdArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { QueryGetPendingInvitationByEntityIdArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { PendingOrgInvitation } from "@local/hash-isomorphic-utils/graphql/api-types.gen"; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/org/invite-user-to-org.ts b/apps/hash-api/src/graphql/resolvers/knowledge/org/invite-user-to-org.ts index 6d4a3d91da5..758c316df7f 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/org/invite-user-to-org.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/org/invite-user-to-org.ts @@ -1,15 +1,8 @@ import dedent from "dedent"; import sanitizeHtml from "sanitize-html"; -import { - type EntityId, - entityIdFromComponents, - type WebId, -} from "@blockprotocol/type-system"; -import { - type HashEntity, - queryEntitySubgraph, -} from "@local/hash-graph-sdk/entity"; +import { type EntityId, entityIdFromComponents, type WebId } from "@blockprotocol/type-system"; +import { type HashEntity, queryEntitySubgraph } from "@local/hash-graph-sdk/entity"; import { getActorGroupRole } from "@local/hash-graph-sdk/principal/actor-group"; import { frontendUrl } from "@local/hash-isomorphic-utils/environment"; import { @@ -26,10 +19,7 @@ import { import { createEntity } from "../../../../graph/knowledge/primitive/entity"; import { createLinkEntity } from "../../../../graph/knowledge/primitive/link-entity"; -import { - getOrgById, - type Org, -} from "../../../../graph/knowledge/system-types/org"; +import { getOrgById, type Org } from "../../../../graph/knowledge/system-types/org"; import { checkEmailVerificationAndUsageStatus, getUser, @@ -59,8 +49,7 @@ const sendOrgEmailInvitationToEmailAddress = async (params: { emailTransporter: EmailTransporter; isSignedUpUser: boolean; }): Promise => { - const { org, invitationId, emailAddress, emailTransporter, isSignedUpUser } = - params; + const { org, invitationId, emailAddress, emailTransporter, isSignedUpUser } = params; const sanitizedOrgName = sanitizeHtml(org.orgName, { allowedTags: [], @@ -143,10 +132,7 @@ const generateExistingInvitationFilter = ( ], }, { - parameter: - invitation.type === "email" - ? invitation.email - : invitation.shortname, + parameter: invitation.type === "email" ? invitation.email : invitation.shortname, }, ], }, @@ -161,24 +147,17 @@ export const inviteUserToOrgResolver: ResolverFn< Record, LoggedInGraphQLContext, MutationInviteUserToOrgArgs -> = async ( - _, - { userEmail: unnormalisedUserEmail, userShortname, orgWebId }, - graphQLContext, -) => { +> = async (_, { userEmail: unnormalisedUserEmail, userShortname, orgWebId }, graphQLContext) => { const { authentication } = graphQLContext; const context = graphQLContextToImpureGraphContext(graphQLContext); let existingUserToInvite: User | null = null; - const userEmail = unnormalisedUserEmail - ? unnormalisedUserEmail.trim().toLowerCase() - : null; + const userEmail = unnormalisedUserEmail ? unnormalisedUserEmail.trim().toLowerCase() : null; if (userEmail) { - const emailCheckResult = - await checkEmailVerificationAndUsageStatus(userEmail); + const emailCheckResult = await checkEmailVerificationAndUsageStatus(userEmail); if (emailCheckResult.status !== "email-not-found") { const existingUser = await getUser(context, authentication, { @@ -202,9 +181,7 @@ export const inviteUserToOrgResolver: ResolverFn< } if (!existingUserToInvite && !userEmail) { - throw Error.badRequest( - "Somehow no user found and no email address provided.", - ); + throw Error.badRequest("Somehow no user found and no email address provided."); } const orgEntityId = entityIdFromComponents(orgWebId, orgWebId); @@ -235,68 +212,50 @@ export const inviteUserToOrgResolver: ResolverFn< }).then((role) => role === "administrator"); if (!isOrgAdmin) { - throw Error.forbidden( - "You must be an administrator to invite users to this organization", - ); + throw Error.forbidden("You must be an administrator to invite users to this organization"); } - const existingInvitations = await queryEntitySubgraph( - context, - authentication, - { - temporalAxes: currentTimeInstantTemporalAxes, - filter: generateExistingInvitationFilter( - orgWebId, - userEmail - ? { - type: "email", - email: userEmail, - } - : { - type: "shortname", - shortname: userShortname!, - }, - ), - traversalPaths: [ - { - edges: [ - { - kind: "has-right-entity", - direction: "incoming", - }, - { - kind: "has-left-entity", - direction: "outgoing", - }, - ], - }, - ], - includeDrafts: false, - includePermissions: false, - }, - ).then(({ subgraph }) => + const existingInvitations = await queryEntitySubgraph(context, authentication, { + temporalAxes: currentTimeInstantTemporalAxes, + filter: generateExistingInvitationFilter( + orgWebId, + userEmail + ? { + type: "email", + email: userEmail, + } + : { + type: "shortname", + shortname: userShortname!, + }, + ), + traversalPaths: [ + { + edges: [ + { + kind: "has-right-entity", + direction: "incoming", + }, + { + kind: "has-left-entity", + direction: "outgoing", + }, + ], + }, + ], + includeDrafts: false, + includePermissions: false, + }).then(({ subgraph }) => getPendingOrgInvitationsFromSubgraph(context, authentication, subgraph), ); let outstandingInvitationCount = existingInvitations.length; - for (const { - expiresAt, - invitationEntity, - linkEntity, - } of existingInvitations) { + for (const { expiresAt, invitationEntity, linkEntity } of existingInvitations) { if (new Date(expiresAt).valueOf() < new Date().valueOf() - 1000 * 60 * 60) { await Promise.all([ - invitationEntity.archive( - context.graphApi, - authentication, - context.provenance, - ), - linkEntity.archive( - context.graphApi, - authentication, - context.provenance, - ), + invitationEntity.archive(context.graphApi, authentication, context.provenance), + linkEntity.archive(context.graphApi, authentication, context.provenance), ]); outstandingInvitationCount--; @@ -323,47 +282,37 @@ export const inviteUserToOrgResolver: ResolverFn< }; if (userEmail) { - invitation = await createEntity( - context, - authentication, - { - entityTypeIds: [systemEntityTypes.invitationViaEmail.entityTypeId], - properties: { - value: { - "https://hash.ai/@h/types/property-type/expired-at/": - expiredAtProperty, - "https://hash.ai/@h/types/property-type/email/": { - value: userEmail, - metadata: { - dataTypeId: systemDataTypes.email.dataTypeId, - }, + invitation = await createEntity(context, authentication, { + entityTypeIds: [systemEntityTypes.invitationViaEmail.entityTypeId], + properties: { + value: { + "https://hash.ai/@h/types/property-type/expired-at/": expiredAtProperty, + "https://hash.ai/@h/types/property-type/email/": { + value: userEmail, + metadata: { + dataTypeId: systemDataTypes.email.dataTypeId, }, }, }, - webId: orgWebId, }, - ); + webId: orgWebId, + }); } else { - invitation = await createEntity( - context, - authentication, - { - entityTypeIds: [systemEntityTypes.invitationViaShortname.entityTypeId], - properties: { - value: { - "https://hash.ai/@h/types/property-type/expired-at/": - expiredAtProperty, - "https://hash.ai/@h/types/property-type/shortname/": { - value: userShortname!, - metadata: { - dataTypeId: blockProtocolDataTypes.text.dataTypeId, - }, + invitation = await createEntity(context, authentication, { + entityTypeIds: [systemEntityTypes.invitationViaShortname.entityTypeId], + properties: { + value: { + "https://hash.ai/@h/types/property-type/expired-at/": expiredAtProperty, + "https://hash.ai/@h/types/property-type/shortname/": { + value: userShortname!, + metadata: { + dataTypeId: blockProtocolDataTypes.text.dataTypeId, }, }, }, - webId: orgWebId, }, - ); + webId: orgWebId, + }); } await createLinkEntity(context, authentication, { @@ -379,9 +328,7 @@ export const inviteUserToOrgResolver: ResolverFn< await sendOrgEmailInvitationToEmailAddress({ org, invitationId: invitation.metadata.recordId.entityId, - emailAddress: existingUserToInvite - ? existingUserToInvite.emails[0]! - : userEmail!, + emailAddress: existingUserToInvite ? existingUserToInvite.emails[0]! : userEmail!, emailTransporter: graphQLContext.emailTransporter, isSignedUpUser: !!existingUserToInvite, }); diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/org/remove-user-from-org.ts b/apps/hash-api/src/graphql/resolvers/knowledge/org/remove-user-from-org.ts index b0b188289f1..c8b2bcf2c37 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/org/remove-user-from-org.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/org/remove-user-from-org.ts @@ -103,11 +103,7 @@ export const removeUserFromOrgResolver: ResolverFn< actorId: extractWebIdFromEntityId(userEntityId) as ActorEntityUuid, actorGroupId: orgWebId, }), - membershipLink.archive( - context.graphApi, - authentication, - context.provenance, - ), + membershipLink.archive(context.graphApi, authentication, context.provenance), ]); return true; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/org/shared.ts b/apps/hash-api/src/graphql/resolvers/knowledge/org/shared.ts index e56150675e7..534ccbe7c8c 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/org/shared.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/org/shared.ts @@ -1,7 +1,4 @@ -import { - getIncomingLinkAndSourceEntities, - getRoots, -} from "@blockprotocol/graph/stdlib"; +import { getIncomingLinkAndSourceEntities, getRoots } from "@blockprotocol/graph/stdlib"; import { type EntityId, entityIdFromComponents, @@ -17,26 +14,17 @@ import { isInvitationByShortname, } from "@local/hash-isomorphic-utils/organization"; -import { - getUser, - type User, -} from "../../../../graph/knowledge/system-types/user"; +import { getUser, type User } from "../../../../graph/knowledge/system-types/user"; import type { ImpureGraphContext } from "../../../../graph/context-types"; -import type { - EntityRootType, - LinkEntityAndLeftEntity, - Subgraph, -} from "@blockprotocol/graph"; +import type { EntityRootType, LinkEntityAndLeftEntity, Subgraph } from "@blockprotocol/graph"; import type { AuthenticationContext } from "@local/hash-graph-sdk/authentication-context"; import type { HashEntity, HashLinkEntity } from "@local/hash-graph-sdk/entity"; import type { PendingOrgInvitation } from "@local/hash-isomorphic-utils/graphql/api-types.gen"; import type { Organization } from "@local/hash-isomorphic-utils/system-types/shared"; const isOrgEntity = (entity: HashEntity): entity is HashEntity => - entity.metadata.entityTypeIds.includes( - systemEntityTypes.organization.entityTypeId, - ); + entity.metadata.entityTypeIds.includes(systemEntityTypes.organization.entityTypeId); export const getPendingOrgInvitationsFromSubgraph = async ( context: ImpureGraphContext, @@ -65,9 +53,7 @@ export const getPendingOrgInvitationsFromSubgraph = async ( const linkEntity = linkAndOrgEntities[0]?.linkEntity[0]; if (!linkEntity) { - throw new Error( - `Pending invitation with entityId ${root.entityId} has no incoming link.`, - ); + throw new Error(`Pending invitation with entityId ${root.entityId} has no incoming link.`); } if ( @@ -100,10 +86,7 @@ export const getPendingOrgInvitationsFromSubgraph = async ( const creatorId = linkEntity.metadata.provenance.createdById; - const invitingUserEntityId = entityIdFromComponents( - creatorId as WebId, - creatorId, - ); + const invitingUserEntityId = entityIdFromComponents(creatorId as WebId, creatorId); const creator = creatorCache[invitingUserEntityId] ?? @@ -134,13 +117,8 @@ export const getPendingOrgInvitationsFromSubgraph = async ( org: { webId: extractWebIdFromEntityId(orgEntity.metadata.recordId.entityId), displayName: - orgEntity.properties[ - "https://hash.ai/@h/types/property-type/organization-name/" - ], - shortname: - orgEntity.properties[ - "https://hash.ai/@h/types/property-type/shortname/" - ], + orgEntity.properties["https://hash.ai/@h/types/property-type/organization-name/"], + shortname: orgEntity.properties["https://hash.ai/@h/types/property-type/shortname/"], }, invitationEntityId: root.entityId, orgToInvitationLinkEntityId: linkEntity.metadata.recordId.entityId, @@ -152,17 +130,14 @@ export const getPendingOrgInvitationsFromSubgraph = async ( pendingInvitations.push({ ...invitationBase, email: root.properties["https://hash.ai/@h/types/property-type/email/"], - expiresAt: - root.properties["https://hash.ai/@h/types/property-type/expired-at/"], + expiresAt: root.properties["https://hash.ai/@h/types/property-type/expired-at/"], invitedAt: root.metadata.provenance.createdAtDecisionTime, }); } else if (isInvitationByShortname(root)) { pendingInvitations.push({ ...invitationBase, - shortname: - root.properties["https://hash.ai/@h/types/property-type/shortname/"], - expiresAt: - root.properties["https://hash.ai/@h/types/property-type/expired-at/"], + shortname: root.properties["https://hash.ai/@h/types/property-type/shortname/"], + expiresAt: root.properties["https://hash.ai/@h/types/property-type/expired-at/"], invitedAt: root.metadata.provenance.createdAtDecisionTime, }); } else { diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/page/page-contents.ts b/apps/hash-api/src/graphql/resolvers/knowledge/page/page-contents.ts index 90aa5ced459..ebb9da31328 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/page/page-contents.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/page/page-contents.ts @@ -25,9 +25,7 @@ export const pageContents: ResolverFn< const contentItems = await getPageBlocks(context, authentication, { pageEntityId: page.metadata.recordId.entityId, - type: page.metadata.entityTypeIds.includes( - systemEntityTypes.canvas.entityTypeId, - ) + type: page.metadata.entityTypeIds.includes(systemEntityTypes.canvas.entityTypeId) ? "canvas" : "document", }); diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/page/page.ts b/apps/hash-api/src/graphql/resolvers/knowledge/page/page.ts index 72edf663c78..dbbf2585572 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/page/page.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/page/page.ts @@ -1,7 +1,4 @@ -import { - createPage, - getPageComments, -} from "../../../../graph/knowledge/system-types/page"; +import { createPage, getPageComments } from "../../../../graph/knowledge/system-types/page"; import { graphQLContextToImpureGraphContext } from "../../util"; import { mapCommentToGQL, mapPageToGQL } from "../graphql-mapping"; @@ -11,21 +8,14 @@ import type { ResolverFn, } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; -import type { - UnresolvedCommentGQL, - UnresolvedPageGQL, -} from "../graphql-mapping"; +import type { UnresolvedCommentGQL, UnresolvedPageGQL } from "../graphql-mapping"; export const createPageResolver: ResolverFn< Promise, Record, LoggedInGraphQLContext, MutationCreatePageArgs -> = async ( - _, - { webId, properties: { title, prevFractionalIndex, type } }, - graphQLContext, -) => { +> = async (_, { webId, properties: { title, prevFractionalIndex, type } }, graphQLContext) => { const context = graphQLContextToImpureGraphContext(graphQLContext); const page = await createPage(context, graphQLContext.authentication, { @@ -46,13 +36,9 @@ export const pageCommentsResolver: ResolverFn< > = async (_, { entityId }, graphQLContext) => { const context = graphQLContextToImpureGraphContext(graphQLContext); - const comments = await getPageComments( - context, - graphQLContext.authentication, - { - pageEntityId: entityId, - }, - ); + const comments = await getPageComments(context, graphQLContext.authentication, { + pageEntityId: entityId, + }); return comments.map(mapCommentToGQL); }; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/page/set-parent-page.ts b/apps/hash-api/src/graphql/resolvers/knowledge/page/set-parent-page.ts index 44fcc10bdf5..23ab1266f3f 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/page/set-parent-page.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/page/set-parent-page.ts @@ -1,15 +1,9 @@ -import { - getPageById, - setPageParentPage, -} from "../../../../graph/knowledge/system-types/page"; +import { getPageById, setPageParentPage } from "../../../../graph/knowledge/system-types/page"; import * as Error from "../../../error"; import { graphQLContextToImpureGraphContext } from "../../util"; import { mapPageToGQL } from "../graphql-mapping"; -import type { - MutationSetParentPageArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationSetParentPageArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { UnresolvedPageGQL } from "../graphql-mapping"; @@ -20,12 +14,7 @@ export const setParentPageResolver: ResolverFn< MutationSetParentPageArgs > = async ( _, - { - pageEntityId, - parentPageEntityId, - prevFractionalIndex = null, - nextIndex = null, - }, + { pageEntityId, parentPageEntityId, prevFractionalIndex = null, nextIndex = null }, graphQLContext, ) => { const { authentication } = graphQLContext; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/page/update-page.ts b/apps/hash-api/src/graphql/resolvers/knowledge/page/update-page.ts index 7a3118f12fe..177930d3e27 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/page/update-page.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/page/update-page.ts @@ -2,17 +2,11 @@ import { mergePropertiesAndMetadata } from "@local/hash-graph-sdk/entity"; import { systemPropertyTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { updateEntity } from "../../../../graph/knowledge/primitive/entity"; -import { - getPageById, - getPageFromEntity, -} from "../../../../graph/knowledge/system-types/page"; +import { getPageById, getPageFromEntity } from "../../../../graph/knowledge/system-types/page"; import { graphQLContextToImpureGraphContext } from "../../util"; import { mapPageToGQL } from "../graphql-mapping"; -import type { - MutationUpdatePageArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationUpdatePageArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { UnresolvedPageGQL } from "../graphql-mapping"; @@ -29,20 +23,17 @@ export const updatePageResolver: ResolverFn< const updatedPageEntity = await updateEntity(context, authentication, { entity: page.entity, - propertyPatches: Object.entries(updatedProperties).map( - ([propertyName, value]) => { - const propertyTypeBaseUrl = - systemPropertyTypes[ - propertyName as keyof MutationUpdatePageArgs["updatedProperties"] - ].propertyTypeBaseUrl; + propertyPatches: Object.entries(updatedProperties).map(([propertyName, value]) => { + const propertyTypeBaseUrl = + systemPropertyTypes[propertyName as keyof MutationUpdatePageArgs["updatedProperties"]] + .propertyTypeBaseUrl; - return { - op: "add", - path: [propertyTypeBaseUrl], - property: mergePropertiesAndMetadata(value, undefined), - }; - }, - ), + return { + op: "add", + path: [propertyTypeBaseUrl], + property: mergePropertiesAndMetadata(value, undefined), + }; + }), }); return mapPageToGQL(getPageFromEntity({ entity: updatedPageEntity })); diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/shared/get-user-permissions-on-subgraph.ts b/apps/hash-api/src/graphql/resolvers/knowledge/shared/get-user-permissions-on-subgraph.ts index 883f9093300..9e9e11a867d 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/shared/get-user-permissions-on-subgraph.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/shared/get-user-permissions-on-subgraph.ts @@ -21,12 +21,8 @@ const werePermissionsRequested = (info: GraphQLResolveInfo) => { } return { - entities: !!( - requestedFieldsOnSubgraph as Record< - keyof SubgraphAndPermissions, - ResolveTree - > - ).userPermissionsOnEntities, + entities: !!(requestedFieldsOnSubgraph as Record) + .userPermissionsOnEntities, }; }; @@ -37,8 +33,7 @@ export const getUserPermissionsOnSubgraph = async ( ): Promise => { const { authentication } = graphQLContext; - const userPermissionsOnEntities = werePermissionsRequested(resolveInfo) - .entities + const userPermissionsOnEntities = werePermissionsRequested(resolveInfo).entities ? await checkPermissionsOnEntitiesInSubgraph( graphQLContextToImpureGraphContext(graphQLContext), authentication, diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/user/get-usage-records.ts b/apps/hash-api/src/graphql/resolvers/knowledge/user/get-usage-records.ts index 3756d93b3d1..fd99db1ec6f 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/user/get-usage-records.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/user/get-usage-records.ts @@ -1,7 +1,4 @@ -import { - type ActorEntityUuid, - extractWebIdFromEntityId, -} from "@blockprotocol/type-system"; +import { type ActorEntityUuid, extractWebIdFromEntityId } from "@blockprotocol/type-system"; import { getWebServiceUsage } from "@local/hash-backend-utils/service-usage"; import { queryEntities } from "@local/hash-graph-sdk/entity"; import { isUserHashInstanceAdmin } from "@local/hash-graph-sdk/principal/hash-instance-admins"; @@ -15,11 +12,7 @@ import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-proper import * as Error from "../../../error"; import { graphQLContextToImpureGraphContext } from "../../util"; -import type { - Query, - ResolverFn, - UserUsageRecords, -} from "../../../api-types.gen"; +import type { Query, ResolverFn, UserUsageRecords } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { UserProperties } from "@local/hash-isomorphic-utils/system-types/user"; @@ -46,10 +39,9 @@ export const getUsageRecordsResolver: ResolverFn< { filter: { all: [ - generateVersionedUrlMatchingFilter( - systemEntityTypes.user.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.user.entityTypeId, { + ignoreParents: true, + }), ], }, temporalAxes: currentTimeInstantTemporalAxes, @@ -63,9 +55,7 @@ export const getUsageRecordsResolver: ResolverFn< for (const user of users) { const { shortname } = simplifyProperties(user.properties as UserProperties); - const userAccountId = extractWebIdFromEntityId( - user.metadata.recordId.entityId, - ); + const userAccountId = extractWebIdFromEntityId(user.metadata.recordId.entityId); const usageRecords = await getWebServiceUsage( { graphApi: dataSources.graphApi }, diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/user/get-waitlist-position.ts b/apps/hash-api/src/graphql/resolvers/knowledge/user/get-waitlist-position.ts index 391c42e9833..113d7d99c08 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/user/get-waitlist-position.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/user/get-waitlist-position.ts @@ -12,9 +12,7 @@ export const getWaitlistPositionResolver: ResolverFn< Record > = async (_, _args, graphQLContext) => { if (isSelfHostedInstance) { - throw new Error( - `This functionality is not relevant to self-hosted instances.`, - ); + throw new Error(`This functionality is not relevant to self-hosted instances.`); } const { user } = graphQLContext; diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/user/is-shortname-taken.ts b/apps/hash-api/src/graphql/resolvers/knowledge/user/is-shortname-taken.ts index 7cf531cc8ec..615770e0749 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/user/is-shortname-taken.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/user/is-shortname-taken.ts @@ -4,10 +4,7 @@ import { } from "../../../../graph/knowledge/system-types/account.fields"; import { graphQLContextToImpureGraphContext } from "../../util"; -import type { - QueryIsShortnameTakenArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { QueryIsShortnameTakenArgs, ResolverFn } from "../../../api-types.gen"; import type { GraphQLContext } from "../../../context"; export const isShortnameTakenResolver: ResolverFn< diff --git a/apps/hash-api/src/graphql/resolvers/knowledge/user/submit-early-access-form.ts b/apps/hash-api/src/graphql/resolvers/knowledge/user/submit-early-access-form.ts index 872bf36c243..462ab243bcc 100644 --- a/apps/hash-api/src/graphql/resolvers/knowledge/user/submit-early-access-form.ts +++ b/apps/hash-api/src/graphql/resolvers/knowledge/user/submit-early-access-form.ts @@ -5,10 +5,7 @@ import { createEntity } from "../../../../graph/knowledge/primitive/entity"; import { systemAccountId } from "../../../../graph/system-account"; import { graphQLContextToImpureGraphContext } from "../../util"; -import type { - MutationSubmitEarlyAccessFormArgs, - ResolverFn, -} from "../../../api-types.gen"; +import type { MutationSubmitEarlyAccessFormArgs, ResolverFn } from "../../../api-types.gen"; import type { LoggedInGraphQLContext } from "../../../context"; import type { WebId } from "@blockprotocol/type-system"; import type { ProspectiveUser } from "@local/hash-isomorphic-utils/system-types/prospectiveuser"; @@ -36,13 +33,9 @@ export const submitEarlyAccessFormResolver: ResolverFn< properties: { value: { "https://hash.ai/@h/types/property-type/current-approach/": { - value: - properties[ - "https://hash.ai/@h/types/property-type/current-approach/" - ], + value: properties["https://hash.ai/@h/types/property-type/current-approach/"], metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/email/": { @@ -52,37 +45,27 @@ export const submitEarlyAccessFormResolver: ResolverFn< }, }, "https://hash.ai/@h/types/property-type/intended-use/": { - value: - properties[ - "https://hash.ai/@h/types/property-type/intended-use/" - ], + value: properties["https://hash.ai/@h/types/property-type/intended-use/"], metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/role/": { value: properties["https://hash.ai/@h/types/property-type/role/"], metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/website-url/": { - value: - properties["https://hash.ai/@h/types/property-type/website-url/"], + value: properties["https://hash.ai/@h/types/property-type/website-url/"], metadata: { dataTypeId: "https://hash.ai/@h/types/data-type/uri/v/1", }, }, "https://hash.ai/@h/types/property-type/willing-to-pay/": { - value: - properties[ - "https://hash.ai/@h/types/property-type/willing-to-pay/" - ], + value: properties["https://hash.ai/@h/types/property-type/willing-to-pay/"], metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, }, diff --git a/apps/hash-api/src/graphql/resolvers/middlewares/middleware-types.ts b/apps/hash-api/src/graphql/resolvers/middlewares/middleware-types.ts index bf72a98530f..7e464d861d8 100644 --- a/apps/hash-api/src/graphql/resolvers/middlewares/middleware-types.ts +++ b/apps/hash-api/src/graphql/resolvers/middlewares/middleware-types.ts @@ -1,10 +1,6 @@ import type { ResolverFn } from "../../api-types.gen"; -export type ResolverMiddleware< - TStartContext, - TArgs, - TEndContext = TStartContext, -> = ( +export type ResolverMiddleware = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any next: ResolverFn, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/apps/hash-api/src/graphql/resolvers/middlewares/signed-up.ts b/apps/hash-api/src/graphql/resolvers/middlewares/signed-up.ts index 84e634d1ebb..e4bc4ec5a98 100644 --- a/apps/hash-api/src/graphql/resolvers/middlewares/signed-up.ts +++ b/apps/hash-api/src/graphql/resolvers/middlewares/signed-up.ts @@ -8,9 +8,7 @@ export const signedUpMiddleware: ResolverMiddleware< Record > = (next) => (obj, args, ctx: LoggedInGraphQLContext, info) => { if (!ctx.user.isAccountSignupComplete) { - throw Error.forbidden( - "You must complete the sign-up process to perform this action.", - ); + throw Error.forbidden("You must complete the sign-up process to perform this action."); } return next(obj, args, ctx, info); }; diff --git a/apps/hash-api/src/graphql/resolvers/ontology/data-type.ts b/apps/hash-api/src/graphql/resolvers/ontology/data-type.ts index edd876c553a..a8b55881bdc 100644 --- a/apps/hash-api/src/graphql/resolvers/ontology/data-type.ts +++ b/apps/hash-api/src/graphql/resolvers/ontology/data-type.ts @@ -26,10 +26,7 @@ import type { ResolverFn, } from "../../api-types.gen"; import type { GraphQLContext, LoggedInGraphQLContext } from "../../context"; -import type { - DataTypeWithMetadata, - OntologyTemporalMetadata, -} from "@blockprotocol/type-system"; +import type { DataTypeWithMetadata, OntologyTemporalMetadata } from "@blockprotocol/type-system"; import type { UserPermissionsOnDataType } from "@local/hash-graph-sdk/authorization"; import type { QueryDataTypesResponse, @@ -143,8 +140,4 @@ export const checkUserPermissionsOnDataTypeResolver: ResolverFn< LoggedInGraphQLContext, QueryCheckUserPermissionsOnDataTypeArgs > = async (_, params, { dataSources, authentication, provenance }) => - checkPermissionsOnDataType( - { ...dataSources, provenance }, - authentication, - params, - ); + checkPermissionsOnDataType({ ...dataSources, provenance }, authentication, params); diff --git a/apps/hash-api/src/graphql/resolvers/ontology/entity-type.ts b/apps/hash-api/src/graphql/resolvers/ontology/entity-type.ts index 4c3baf987fa..7956343b4f2 100644 --- a/apps/hash-api/src/graphql/resolvers/ontology/entity-type.ts +++ b/apps/hash-api/src/graphql/resolvers/ontology/entity-type.ts @@ -133,11 +133,7 @@ export const checkUserPermissionsOnEntityTypeResolver: ResolverFn< LoggedInGraphQLContext, QueryCheckUserPermissionsOnEntityTypeArgs > = async (_, params, { dataSources, authentication, provenance }) => - checkPermissionsOnEntityType( - { ...dataSources, provenance }, - authentication, - params, - ); + checkPermissionsOnEntityType({ ...dataSources, provenance }, authentication, params); export const archiveEntityTypeResolver: ResolverFn< Promise, diff --git a/apps/hash-api/src/graphql/resolvers/ontology/property-type.ts b/apps/hash-api/src/graphql/resolvers/ontology/property-type.ts index 0f52e150014..c7c387608bc 100644 --- a/apps/hash-api/src/graphql/resolvers/ontology/property-type.ts +++ b/apps/hash-api/src/graphql/resolvers/ontology/property-type.ts @@ -42,14 +42,10 @@ export const createPropertyTypeResolver: ResolverFn< const { webId, propertyType } = params; - const createdPropertyType = await createPropertyType( - context, - authentication, - { - webId: (webId ?? user.accountId) as WebId, - schema: propertyType, - }, - ); + const createdPropertyType = await createPropertyType(context, authentication, { + webId: (webId ?? user.accountId) as WebId, + schema: propertyType, + }); return createdPropertyType; }; diff --git a/apps/hash-api/src/index.ts b/apps/hash-api/src/index.ts index 573cb5bbbb5..7a8a0e103f4 100644 --- a/apps/hash-api/src/index.ts +++ b/apps/hash-api/src/index.ts @@ -12,11 +12,7 @@ import { create as handlebarsCreate } from "express-handlebars"; import { ipKeyGenerator, rateLimit } from "express-rate-limit"; import helmet from "helmet"; import { StatsD } from "hot-shots"; -import { - createProxyMiddleware, - fixRequestBody, - responseInterceptor, -} from "http-proxy-middleware"; +import { createProxyMiddleware, fixRequestBody, responseInterceptor } from "http-proxy-middleware"; import httpTerminator from "http-terminator"; import Keyv from "keyv"; import { customAlphabet } from "nanoid"; @@ -72,25 +68,11 @@ import { googleOAuthCallback } from "./integrations/google/oauth-callback"; import { oAuthLinear, oAuthLinearCallback } from "./integrations/linear/oauth"; import { linearWebhook } from "./integrations/linear/webhook"; import { createIntegrationSyncBackWatcher } from "./integrations/sync-back-watcher"; -import { - CORS_CONFIG, - getEnvStorageType, - GRAPHQL_PATH, - LOCAL_FILE_UPLOAD_PATH, -} from "./lib/config"; -import { - isDevEnv, - isProdEnv, - isStatsDEnabled, - isTestEnv, - port, -} from "./lib/env-config"; +import { CORS_CONFIG, getEnvStorageType, GRAPHQL_PATH, LOCAL_FILE_UPLOAD_PATH } from "./lib/config"; +import { isDevEnv, isProdEnv, isStatsDEnabled, isTestEnv, port } from "./lib/env-config"; import { logger } from "./logger"; import { seedOrgsAndUsers } from "./seed-data"; -import { - setupFileDownloadProxyHandler, - setupStorageProviders, -} from "./storage"; +import { setupFileDownloadProxyHandler, setupStorageProviders } from "./storage"; import { setupTelemetry } from "./telemetry/snowplow-setup"; import type { ProvidedEntityEditionProvenance } from "@blockprotocol/type-system"; @@ -253,9 +235,7 @@ const redactAuthQueryParams = (value: string): string => .replace(/\?[^#\s]*/g, "?[REDACTED_QUERY]"); const sanitizeProxyLogArgs = (args: unknown[]): unknown[] => - args.map((arg) => - typeof arg === "string" ? redactAuthQueryParams(arg) : arg, - ); + args.map((arg) => (typeof arg === "string" ? redactAuthQueryParams(arg) : arg)); /** * Forward a `http-proxy-middleware` variadic log call to the @@ -321,9 +301,7 @@ const kratosProxy = createProxyMiddleware({ * in modern browsers. */ proxyRes: (proxyRes, req, res) => { - const expectedAccessControlAllowOriginHeader = res.getHeader( - "access-control-allow-origin", - ); + const expectedAccessControlAllowOriginHeader = res.getHeader("access-control-allow-origin"); return responseInterceptor((responseBuffer, _, __, inflightRes) => { if (typeof expectedAccessControlAllowOriginHeader === "string") { @@ -408,9 +386,7 @@ const main = async () => { origin: req.headers.origin, ip: req.ip, userAgent: req.headers["user-agent"], - graphqlClient: - req.headers[hashClientHeaderKey] ?? - req.headers["apollographql-client-name"], + graphqlClient: req.headers[hashClientHeaderKey] ?? req.headers["apollographql-client-name"], }); } @@ -419,15 +395,11 @@ const main = async () => { const redisHost = getRequiredEnv("HASH_REDIS_HOST"); const redisPort = Number.parseInt(getRequiredEnv("HASH_REDIS_PORT"), 10); - const redisEncryptedTransit = - process.env.HASH_REDIS_ENCRYPTED_TRANSIT === "true"; + const redisEncryptedTransit = process.env.HASH_REDIS_ENCRYPTED_TRANSIT === "true"; const redisUrl = `redis${redisEncryptedTransit ? "s" : ""}://${redisHost}:${redisPort}`; const graphApiHost = getRequiredEnv("HASH_GRAPH_HTTP_HOST"); - const graphApiPort = Number.parseInt( - getRequiredEnv("HASH_GRAPH_HTTP_PORT"), - 10, - ); + const graphApiPort = Number.parseInt(getRequiredEnv("HASH_GRAPH_HTTP_PORT"), 10); await Promise.all([ waitOnResource(`tcp:${redisHost}:${redisPort}`, logger), @@ -526,11 +498,7 @@ const main = async () => { "https://apollo-server-landing-page.cdn.apollographql.com", ], styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"], - imgSrc: [ - "'self'", - "data:", - "https://apollo-server-landing-page.cdn.apollographql.com", - ], + imgSrc: ["'self'", "data:", "https://apollo-server-landing-page.cdn.apollographql.com"], connectSrc: [ "'self'", "https://apollo-server-landing-page.cdn.apollographql.com", @@ -538,10 +506,7 @@ const main = async () => { ], frameSrc: ["'self'", "https://sandbox.embed.apollographql.com"], fontSrc: ["'self'", "https://fonts.gstatic.com"], - manifestSrc: [ - "'self'", - "https://apollo-server-landing-page.cdn.apollographql.com", - ], + manifestSrc: ["'self'", "https://apollo-server-landing-page.cdn.apollographql.com"], ...cspHardeningDirectives, }, }, @@ -596,10 +561,7 @@ const main = async () => { /** Body parsing middleware */ app.use((req, res, next) => { - if ( - req.path.startsWith("/webhooks/") || - req.path === LOCAL_FILE_UPLOAD_PATH - ) { + if (req.path.startsWith("/webhooks/") || req.path === LOCAL_FILE_UPLOAD_PATH) { // webhooks typically need the raw body for signature verification return rawParser(req, res, next); } @@ -666,11 +628,7 @@ const main = async () => { /** OAuth2 consent flow */ app.get("/oauth2/consent", authRouteRateLimiter, oauthConsentRequestHandler); - app.post( - "/oauth2/consent", - authRouteRateLimiter, - oauthConsentSubmissionHandler, - ); + app.post("/oauth2/consent", authRouteRateLimiter, oauthConsentSubmissionHandler); const hbs = handlebarsCreate({ defaultLayout: "main", extname: ".hbs" }); app.engine( @@ -766,10 +724,7 @@ const main = async () => { shutdown.addCleanup("ManagedRuntime", () => runtime.dispose()); const rpcHost = getRequiredEnv("HASH_GRAPH_RPC_HOST"); - const rpcPort = Number.parseInt( - process.env.HASH_GRAPH_RPC_PORT ?? "4002", - 10, - ); + const rpcPort = Number.parseInt(process.env.HASH_GRAPH_RPC_PORT ?? "4002", 10); // print out (temporary) DNS diagnostics // see: https://linear.app/hash/issue/H-3813/remove-dns-logging-durring-hash-api-start @@ -801,18 +756,14 @@ const main = async () => { const effect = Effect.gen(function* () { const textQueryParam = req.query.text; if (typeof textQueryParam !== "string") { - return yield* new RuntimeException( - "text query parameter is required", - ); + return yield* new RuntimeException("text query parameter is required"); } const response = yield* EchoSubsystem.echo(textQueryParam); res.status(200).send(response); }).pipe( Effect.provide( - RpcClient.connectLayer( - Transport.multiaddr(`/dns/${rpcHost}/tcp/${rpcPort}`), - ), + RpcClient.connectLayer(Transport.multiaddr(`/dns/${rpcHost}/tcp/${rpcPort}`)), ), Logger.withMinimumLogLevel(LogLevel.Trace), ); @@ -850,21 +801,13 @@ const main = async () => { app.post("/oauth/google/callback", authRouteRateLimiter, googleOAuthCallback); app.post("/oauth/google/token", authRouteRateLimiter, getGoogleAccessToken); - app.post( - "/oauth/google/check-token", - authRouteRateLimiter, - checkGoogleAccessToken, - ); + app.post("/oauth/google/check-token", authRouteRateLimiter, checkGoogleAccessToken); // Endpoints used by HashGPT or in support of it app.post("/gpt/entities/query", gptRateLimiter, gptQueryEntities); app.post("/gpt/entities/query-types", gptRateLimiter, gptQueryTypes); app.get("/gpt/user-webs", gptRateLimiter, gptGetUserWebs); - app.post( - "/gpt/upsert-gpt-oauth-client", - gptRateLimiter, - upsertGptOauthClient, - ); + app.post("/gpt/upsert-gpt-oauth-client", gptRateLimiter, upsertGptOauthClient); /** * This middleware MUST: @@ -958,10 +901,7 @@ const main = async () => { void integrationSyncBackWatcher.start(); - shutdown.addCleanup( - "Integration sync back watcher", - integrationSyncBackWatcher.stop, - ); + shutdown.addCleanup("Integration sync back watcher", integrationSyncBackWatcher.stop); } }; diff --git a/apps/hash-api/src/instrument.mjs b/apps/hash-api/src/instrument.mjs index 9f48bdef97d..3d5e0bdacc0 100644 --- a/apps/hash-api/src/instrument.mjs +++ b/apps/hash-api/src/instrument.mjs @@ -1,9 +1,6 @@ /** Required to load environment variables */ import "@local/hash-backend-utils/environment"; -import { - ExpressInstrumentation, - ExpressLayerType, -} from "@opentelemetry/instrumentation-express"; +import { ExpressInstrumentation, ExpressLayerType } from "@opentelemetry/instrumentation-express"; import { GraphQLInstrumentation } from "@opentelemetry/instrumentation-graphql"; import * as Sentry from "@sentry/node"; @@ -59,10 +56,7 @@ export const otelSetup = (() => { throw error; } // eslint-disable-next-line no-console - console.error( - "OpenTelemetry bootstrap failed; service will start without telemetry.", - error, - ); + console.error("OpenTelemetry bootstrap failed; service will start without telemetry.", error); return undefined; } })(); diff --git a/apps/hash-api/src/integrations/enabled-integrations.ts b/apps/hash-api/src/integrations/enabled-integrations.ts index 5372c3115e2..86d25f0c428 100644 --- a/apps/hash-api/src/integrations/enabled-integrations.ts +++ b/apps/hash-api/src/integrations/enabled-integrations.ts @@ -3,7 +3,5 @@ export const enabledIntegrations = { !!process.env.LINEAR_CLIENT_ID && !!process.env.LINEAR_CLIENT_SECRET && !!process.env.LINEAR_WEBHOOK_SECRET, - googleSheets: - !!process.env.GOOGLE_OAUTH_CLIENT_ID && - !!process.env.GOOGLE_OAUTH_CLIENT_SECRET, + googleSheets: !!process.env.GOOGLE_OAUTH_CLIENT_ID && !!process.env.GOOGLE_OAUTH_CLIENT_SECRET, } as const satisfies Record; diff --git a/apps/hash-api/src/integrations/google/oauth-callback.ts b/apps/hash-api/src/integrations/google/oauth-callback.ts index 9310243169d..7917f24f35d 100644 --- a/apps/hash-api/src/integrations/google/oauth-callback.ts +++ b/apps/hash-api/src/integrations/google/oauth-callback.ts @@ -1,10 +1,7 @@ import { google } from "googleapis"; import { NotFoundError } from "@local/hash-backend-utils/error"; -import { - createGoogleOAuth2Client, - getGoogleAccountById, -} from "@local/hash-backend-utils/google"; +import { createGoogleOAuth2Client, getGoogleAccountById } from "@local/hash-backend-utils/google"; import { getMachineIdByIdentifier } from "@local/hash-backend-utils/machine-actors"; import { googleEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; @@ -75,11 +72,9 @@ export const googleOAuthCallback: RequestHandler< const authentication = { actorId: req.user.accountId }; - const googleBotAccountId = await getMachineIdByIdentifier( - req.context, - authentication, - { identifier: "google" }, - ).then((maybeMachineId) => { + const googleBotAccountId = await getMachineIdByIdentifier(req.context, authentication, { + identifier: "google", + }).then((maybeMachineId) => { if (!maybeMachineId) { throw new NotFoundError("Failed to get google bot"); } @@ -105,19 +100,16 @@ export const googleOAuthCallback: RequestHandler< dataTypeId: "https://hash.ai/@h/types/data-type/email/v/1", }, }, - "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": - { - value: googleUser.data.name ?? googleUser.data.email, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + "https://blockprotocol.org/@blockprotocol/types/property-type/display-name/": { + value: googleUser.data.name ?? googleUser.data.email, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, + }, "https://hash.ai/@google/types/property-type/account-id/": { value: googleUser.data.id, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, }, @@ -130,8 +122,7 @@ export const googleOAuthCallback: RequestHandler< }); } - const googleAccountEntity = - existingGoogleAccountEntity ?? newGoogleAccountEntity; + const googleAccountEntity = existingGoogleAccountEntity ?? newGoogleAccountEntity; if (!googleAccountEntity) { res.status(500).send({ @@ -158,9 +149,7 @@ export const googleOAuthCallback: RequestHandler< */ archiveExistingSecrets: true, // Set the expiration to 5 years from now (in ISO format) - expiresAt: new Date( - Date.now() + 5 * 365 * 24 * 60 * 60 * 1000, - ).toISOString(), // the secret data includes a refresh token that lasts indefinitely and will be used as needed + expiresAt: new Date(Date.now() + 5 * 365 * 24 * 60 * 60 * 1000).toISOString(), // the secret data includes a refresh token that lasts indefinitely and will be used as needed graphApi: req.context.graphApi, managingBotAccountId: googleBotAccountId, provenance: req.context.provenance, diff --git a/apps/hash-api/src/integrations/linear.ts b/apps/hash-api/src/integrations/linear.ts index 0d503a0bbab..37891bbc32f 100644 --- a/apps/hash-api/src/integrations/linear.ts +++ b/apps/hash-api/src/integrations/linear.ts @@ -7,9 +7,7 @@ import type { Organization, Team } from "@linear/sdk"; import type { TemporalClient } from "@local/hash-backend-utils/temporal"; import type { SyncWebWorkflow } from "@local/hash-backend-utils/temporal-integration-workflow-types"; -export const listTeams = async (params: { - apiKey: string; -}): Promise => { +export const listTeams = async (params: { apiKey: string }): Promise => { const { apiKey } = params; const linearClient = new LinearClient({ apiKey }); @@ -23,9 +21,7 @@ export const listTeams = async (params: { return teams; }; -export const getOrganization = async (params: { - apiKey: string; -}): Promise => { +export const getOrganization = async (params: { apiKey: string }): Promise => { const { apiKey } = params; const linearClient = new LinearClient({ apiKey }); @@ -50,18 +46,15 @@ export class Linear { teamIds: string[]; }): Promise { // TODO: Implement error handling - await this.temporalClient.workflow.start( - "syncLinearToWeb", - { - taskQueue: "integration", - args: [ - { - apiKey: this.apiKey, - ...params, - }, - ], - workflowId: `syncLinearToWeb-${generateUuid()}`, - }, - ); + await this.temporalClient.workflow.start("syncLinearToWeb", { + taskQueue: "integration", + args: [ + { + apiKey: this.apiKey, + ...params, + }, + ], + workflowId: `syncLinearToWeb-${generateUuid()}`, + }); } } diff --git a/apps/hash-api/src/integrations/linear/oauth.ts b/apps/hash-api/src/integrations/linear/oauth.ts index 084fbe86f57..8347fa6bb19 100644 --- a/apps/hash-api/src/integrations/linear/oauth.ts +++ b/apps/hash-api/src/integrations/linear/oauth.ts @@ -4,10 +4,7 @@ import { LinearClient } from "@linear/sdk"; import { extractEntityUuidFromEntityId } from "@blockprotocol/type-system"; import { getMachineIdByIdentifier } from "@local/hash-backend-utils/machine-actors"; -import { - apiOrigin, - frontendUrl, -} from "@local/hash-isomorphic-utils/environment"; +import { apiOrigin, frontendUrl } from "@local/hash-isomorphic-utils/environment"; import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid"; import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; @@ -20,13 +17,7 @@ import { isUserMemberOfOrg } from "../../graph/knowledge/system-types/user"; import { createUserSecret } from "../../graph/knowledge/system-types/user-secret"; import type { LinearIntegration } from "../../graph/knowledge/system-types/linear-integration-entity"; -import type { - Entity, - EntityId, - EntityUuid, - UserId, - WebId, -} from "@blockprotocol/type-system"; +import type { Entity, EntityId, EntityUuid, UserId, WebId } from "@blockprotocol/type-system"; import type { LinearIntegrationPropertiesWithMetadata } from "@local/hash-isomorphic-utils/system-types/linearintegration"; import type { RequestHandler } from "express"; @@ -70,11 +61,7 @@ export const oAuthLinear: RequestHandler< } > = async (req, res) => { if (!linearClientId) { - res - .status(501) - .send( - "Linear integration is not configured – set a client id and secret.", - ); + res.status(501).send("Linear integration is not configured – set a client id and secret."); return; } @@ -100,11 +87,7 @@ export const oAuthLinear: RequestHandler< orgEntityUuid: webId as EntityUuid, })) ) { - res - .status(403) - .send( - "webId must represent the user or an organization they are a member of.", - ); + res.status(403).send("webId must represent the user or an organization they are a member of."); return; } @@ -177,10 +160,7 @@ export const oAuthLinearCallback: RequestHandler< headers: { "content-type": "application/x-www-form-urlencoded", }, - }).then( - (resp) => - resp.json() as Promise<{ access_token: string; expires_in: number }>, - ); + }).then((resp) => resp.json() as Promise<{ access_token: string; expires_in: number }>); const { access_token, expires_in } = response; @@ -202,11 +182,9 @@ export const oAuthLinearCallback: RequestHandler< /** * Get the linear bot, which will be the only entity with edit access to the secret and the link to the secret */ - const linearBotAccountId = await getMachineIdByIdentifier( - req.context, - authentication, - { identifier: "linear" }, - ).then((maybeMachineId) => { + const linearBotAccountId = await getMachineIdByIdentifier(req.context, authentication, { + identifier: "linear", + }).then((maybeMachineId) => { if (!maybeMachineId) { throw new Error("Failed to get linear bot"); } @@ -226,31 +204,25 @@ export const oAuthLinearCallback: RequestHandler< if (existingLinearIntegration) { linearIntegration = existingLinearIntegration; } else { - const linearIntegrationProperties: LinearIntegrationPropertiesWithMetadata = - { - value: { - "https://hash.ai/@h/types/property-type/linear-org-id/": { - value: linearOrgId, - metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", - }, + const linearIntegrationProperties: LinearIntegrationPropertiesWithMetadata = { + value: { + "https://hash.ai/@h/types/property-type/linear-org-id/": { + value: linearOrgId, + metadata: { + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, - }; + }, + }; // Create the Linear integration entity, which any web member can view and edit const entityUuid = generateUuid() as EntityUuid; - const linearIntegrationEntity = await createEntity( - req.context, - authentication, - { - entityTypeIds: [systemEntityTypes.linearIntegration.entityTypeId], - webId: userAccountId as WebId, - entityUuid, - properties: linearIntegrationProperties, - }, - ); + const linearIntegrationEntity = await createEntity(req.context, authentication, { + entityTypeIds: [systemEntityTypes.linearIntegration.entityTypeId], + webId: userAccountId as WebId, + entityUuid, + properties: linearIntegrationProperties, + }); linearIntegration = getLinearIntegrationFromEntity({ entity: linearIntegrationEntity, @@ -269,8 +241,7 @@ export const oAuthLinearCallback: RequestHandler< restOfPath: `workspace/${linearOrgId}`, secretData: { value: access_token }, service: "linear", - sourceIntegrationEntityId: - linearIntegration.entity.metadata.recordId.entityId, + sourceIntegrationEntityId: linearIntegration.entity.metadata.recordId.entityId, userAccountId: req.user.accountId, vaultClient: req.context.vaultClient, }); diff --git a/apps/hash-api/src/integrations/linear/sync-back.ts b/apps/hash-api/src/integrations/linear/sync-back.ts index 083d36b0f8f..7c89d76d744 100644 --- a/apps/hash-api/src/integrations/linear/sync-back.ts +++ b/apps/hash-api/src/integrations/linear/sync-back.ts @@ -1,7 +1,4 @@ -import { - entityIdFromComponents, - extractWebIdFromEntityId, -} from "@blockprotocol/type-system"; +import { entityIdFromComponents, extractWebIdFromEntityId } from "@blockprotocol/type-system"; import { linearTypeMappings } from "@local/hash-backend-utils/linear-type-mappings"; import { getMachineIdByIdentifier } from "@local/hash-backend-utils/machine-actors"; import { createTemporalClient } from "@local/hash-backend-utils/temporal"; @@ -23,11 +20,8 @@ const supportedLinearEntityTypeIds = linearTypeMappings.map( ({ hashEntityTypeId }) => hashEntityTypeId as VersionedUrl, ); -const supportedLinearLinkEntityTypeIds = linearTypeMappings.flatMap( - ({ outgoingLinkMappings }) => - outgoingLinkMappings.map( - ({ linkEntityTypeId }) => linkEntityTypeId as VersionedUrl, - ), +const supportedLinearLinkEntityTypeIds = linearTypeMappings.flatMap(({ outgoingLinkMappings }) => + outgoingLinkMappings.map(({ linkEntityTypeId }) => linkEntityTypeId as VersionedUrl), ); export const supportedLinearTypeIds = [ @@ -46,11 +40,7 @@ export const processEntityChange = async ({ }) => { const { entityTypeIds } = entity.metadata; - if ( - !entityTypeIds.some( - (entityTypeId) => !supportedLinearTypeIds.includes(entityTypeId), - ) - ) { + if (!entityTypeIds.some((entityTypeId) => !supportedLinearTypeIds.includes(entityTypeId))) { throw new Error( `Entity with entity type(s) ${entityTypeIds.join(", ")} passed to Linear sync back processor – supported types are ${supportedLinearEntityTypeIds.join( ", ", @@ -127,27 +117,23 @@ export const processEntityChange = async ({ }, ); - const linearId = - linearEntityToUpdate.properties[linearPropertyTypes.id.propertyTypeBaseUrl]; + const linearId = linearEntityToUpdate.properties[linearPropertyTypes.id.propertyTypeBaseUrl]; if (!linearId) { return; } - await temporalClient.workflow.start( - "updateLinearData", - { - workflowId: generateUuid(), - taskQueue: "integration", - args: [ - { - apiKey: linearApiKey, - linearId: linearId as string, - authentication: { actorId: linearMachineActorId }, - entityTypeIds: linearEntityToUpdate.metadata.entityTypeIds, - entity: linearEntityToUpdate.toJSON(), - }, - ], - }, - ); + await temporalClient.workflow.start("updateLinearData", { + workflowId: generateUuid(), + taskQueue: "integration", + args: [ + { + apiKey: linearApiKey, + linearId: linearId as string, + authentication: { actorId: linearMachineActorId }, + entityTypeIds: linearEntityToUpdate.metadata.entityTypeIds, + entity: linearEntityToUpdate.toJSON(), + }, + ], + }); }; diff --git a/apps/hash-api/src/integrations/linear/webhook.ts b/apps/hash-api/src/integrations/linear/webhook.ts index c4482cc0ecb..a7afcae9a76 100644 --- a/apps/hash-api/src/integrations/linear/webhook.ts +++ b/apps/hash-api/src/integrations/linear/webhook.ts @@ -33,21 +33,17 @@ type LinearWebhookPayload = { webhookTimestamp: number; // UNIX timestamp of webhook delivery in milliseconds. }; -export const linearWebhook: RequestHandler< - Record, - string, - string -> = async (req, res) => { +export const linearWebhook: RequestHandler, string, string> = async ( + req, + res, +) => { const secret = process.env.LINEAR_WEBHOOK_SECRET; if (!secret) { throw new Error("LINEAR_WEBHOOK_SECRET is not set"); } - const expectedSignature = crypto - .createHmac("sha256", secret) - .update(req.body) - .digest("hex"); + const expectedSignature = crypto.createHmac("sha256", secret).update(req.body).digest("hex"); const linearSignature = req.headers["linear-signature"]; if ( @@ -65,20 +61,14 @@ export const linearWebhook: RequestHandler< const organizationId = payload.organizationId; if (!payload.data) { - res - .status(400) - .send( - `No data sent with ${payload.action} ${payload.type} webhook payload`, - ); + res.status(400).send(`No data sent with ${payload.action} ${payload.type} webhook payload`); return; } const linearId = payload.data.id; if (!linearId) { - res - .status(400) - .send(`No ID found in ${payload.action} ${payload.type} webhook payload`); + res.status(400).send(`No ID found in ${payload.action} ${payload.type} webhook payload`); return; } @@ -132,8 +122,7 @@ export const linearWebhook: RequestHandler< graphContext, { actorId: linearBotAccountId }, { - linearIntegrationEntityId: - linearIntegration.entity.metadata.recordId.entityId, + linearIntegrationEntityId: linearIntegration.entity.metadata.recordId.entityId, }, ); @@ -147,9 +136,7 @@ export const linearWebhook: RequestHandler< const hashWebEntityId = web.webEntity.metadata.recordId.entityId; - const webId = extractEntityUuidFromEntityId( - hashWebEntityId, - ) as string as WebId; + const webId = extractEntityUuidFromEntityId(hashWebEntityId) as string as WebId; const workflow = `${payloadAction}HashEntityFromLinearData` as const satisfies keyof WorkflowTypeMap; @@ -163,9 +150,7 @@ export const linearWebhook: RequestHandler< }, ); - await temporalClient.workflow.start< - WorkflowTypeMap[typeof workflow] - >(workflow, { + await temporalClient.workflow.start(workflow, { taskQueue: "integration", args: [ { diff --git a/apps/hash-api/src/lib/config.ts b/apps/hash-api/src/lib/config.ts index 38b62a55b53..3bc33ca374b 100644 --- a/apps/hash-api/src/lib/config.ts +++ b/apps/hash-api/src/lib/config.ts @@ -18,8 +18,7 @@ export function getEnvStorageType(): StorageType { ); } -export const LOCAL_FILE_UPLOAD_PATH = - process.env.LOCAL_FILE_UPLOAD_PATH || "var/uploads/"; +export const LOCAL_FILE_UPLOAD_PATH = process.env.LOCAL_FILE_UPLOAD_PATH || "var/uploads/"; export const GRAPHQL_PATH = "/graphql"; @@ -43,13 +42,9 @@ const defaultCorsOrigins: corsMiddleware.CorsOptions["origin"] = [ * * Both accept comma-separated origin strings. */ -const corsOrigins: corsMiddleware.CorsOptions["origin"] = process.env - .HASH_CORS_ORIGIN_OVERRIDE +const corsOrigins: corsMiddleware.CorsOptions["origin"] = process.env.HASH_CORS_ORIGIN_OVERRIDE ? parseCorsOrigins(process.env.HASH_CORS_ORIGIN_OVERRIDE) - : [ - ...defaultCorsOrigins, - ...parseCorsOrigins(process.env.HASH_CORS_ADDITIONAL_ORIGINS ?? ""), - ]; + : [...defaultCorsOrigins, ...parseCorsOrigins(process.env.HASH_CORS_ADDITIONAL_ORIGINS ?? "")]; export const CORS_CONFIG: corsMiddleware.CorsOptions = { credentials: true, diff --git a/apps/hash-api/src/lib/env-config.ts b/apps/hash-api/src/lib/env-config.ts index c36e203601a..2e64a9e4377 100644 --- a/apps/hash-api/src/lib/env-config.ts +++ b/apps/hash-api/src/lib/env-config.ts @@ -6,8 +6,7 @@ const PORT = process.env.PORT; export const isTestEnv = process.env.NODE_ENV === "test"; /** Whether the backend is running in the development environment. */ -export const isDevEnv = - process.env.NODE_ENV === "development" || !process.env.NODE_ENV; +export const isDevEnv = process.env.NODE_ENV === "development" || !process.env.NODE_ENV; /** Whether the backend is running in the production environment. */ export const isProdEnv = process.env.NODE_ENV === "production"; diff --git a/apps/hash-api/src/mailchimp.ts b/apps/hash-api/src/mailchimp.ts index e0af99ac21e..b9d3bb30191 100644 --- a/apps/hash-api/src/mailchimp.ts +++ b/apps/hash-api/src/mailchimp.ts @@ -39,13 +39,9 @@ export const createOrUpdateMailchimpUser = async (params: { if (error.response.body.title === "Member Exists") { const subscriberHash = md5(email.toLowerCase()); - await mailchimp.lists.updateListMember( - mailchimpListId, - subscriberHash, - { - merge_fields, - }, - ); + await mailchimp.lists.updateListMember(mailchimpListId, subscriberHash, { + merge_fields, + }); } }); } catch (error) { diff --git a/apps/hash-api/src/seed-data/index.ts b/apps/hash-api/src/seed-data/index.ts index 9db3c9fc39f..95d5011f451 100644 --- a/apps/hash-api/src/seed-data/index.ts +++ b/apps/hash-api/src/seed-data/index.ts @@ -1,9 +1,6 @@ import { extractWebIdFromEntityId } from "@blockprotocol/type-system"; -import { - createOrg, - getOrgByShortname, -} from "../graph/knowledge/system-types/org"; +import { createOrg, getOrgByShortname } from "../graph/knowledge/system-types/org"; import { createOrgMembershipLinkEntity } from "../graph/knowledge/system-types/org-membership"; import { joinOrg } from "../graph/knowledge/system-types/user"; import { seedPages } from "./seed-pages"; @@ -40,9 +37,7 @@ const seedOrg = async (params: { shortname: exampleOrgShortname, }); - logger.info( - `Development Org available with shortname = "${sharedOrg.shortname}"`, - ); + logger.info(`Development Org available with shortname = "${sharedOrg.shortname}"`); const pageTitles: PageDefinition[] = [ { @@ -58,9 +53,7 @@ const seedOrg = async (params: { await seedPages(authentication, pageTitles, sharedOrg.webId, params); - logger.info( - `Development Org with shortname = "${sharedOrg.shortname}" now has seeded pages.`, - ); + logger.info(`Development Org with shortname = "${sharedOrg.shortname}" now has seeded pages.`); return sharedOrg; }; @@ -74,17 +67,12 @@ export const seedOrgsAndUsers = async (params: { const createdUsers = await ensureUsersAreSeeded(params); if (createdUsers.length > 0) { - const orgOwner = createdUsers.find( - ({ shortname }) => shortname === "alice", - )!; + const orgOwner = createdUsers.find(({ shortname }) => shortname === "alice")!; const sharedOrg = await seedOrg({ ...params, owner: orgOwner }); for (const user of createdUsers) { - if ( - extractWebIdFromEntityId(user.entity.metadata.recordId.entityId) !== - orgOwner.accountId - ) { + if (extractWebIdFromEntityId(user.entity.metadata.recordId.entityId) !== orgOwner.accountId) { /** * For users who AREN'T the org owner, we need to create their full membership, * including both the permission system membership, and the link entity in the graph. @@ -145,15 +133,8 @@ export const seedOrgsAndUsers = async (params: { }, ]; - await seedPages( - { actorId: user.accountId }, - pageTitles, - user.accountId, - params, - ); - logger.info( - `Seeded User with shortname = "${user.shortname}" now has seeded pages.`, - ); + await seedPages({ actorId: user.accountId }, pageTitles, user.accountId, params); + logger.info(`Seeded User with shortname = "${user.shortname}" now has seeded pages.`); } } }; diff --git a/apps/hash-api/src/seed-data/seed-flow-test-types.ts b/apps/hash-api/src/seed-data/seed-flow-test-types.ts index 9a99b34d22e..be7cdb67ce5 100644 --- a/apps/hash-api/src/seed-data/seed-flow-test-types.ts +++ b/apps/hash-api/src/seed-data/seed-flow-test-types.ts @@ -25,10 +25,7 @@ import { generateSystemPropertyTypeSchema, generateSystemTypeBaseUrl, } from "../graph/ensure-system-graph-is-initialized/migrate-ontology-types/util"; -import { - createOrg, - getOrgByShortname, -} from "../graph/knowledge/system-types/org"; +import { createOrg, getOrgByShortname } from "../graph/knowledge/system-types/org"; import { createEntityType } from "../graph/ontology/primitive/entity-type"; import { createPropertyType } from "../graph/ontology/primitive/property-type"; import { logger } from "../logger"; @@ -66,11 +63,10 @@ const createSystemPropertyTypeIfNotExists: ImpureGraphFunction< const propertyTypeId = versionedUrlFromComponents(baseUrl, versionNumber); - const existingPropertyType = await getPropertyTypeById( - context.graphApi, - authentication, - { propertyTypeId, temporalAxes: currentTimeInstantTemporalAxes }, - ); + const existingPropertyType = await getPropertyTypeById(context.graphApi, authentication, { + propertyTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (existingPropertyType) { return existingPropertyType; @@ -81,15 +77,11 @@ const createSystemPropertyTypeIfNotExists: ImpureGraphFunction< propertyTypeId, }); - const createdPropertyType = await createPropertyType( - context, - authentication, - { - webId, - schema: propertyTypeSchema, - webShortname, - }, - ).catch((createError) => { + const createdPropertyType = await createPropertyType(context, authentication, { + webId, + schema: propertyTypeSchema, + webShortname, + }).catch((createError) => { throw createError; }); @@ -114,14 +106,10 @@ const createSystemEntityTypeIfNotExists: ImpureGraphFunction< const entityTypeId = versionedUrlFromComponents(baseUrl, versionNumber); - const existingEntityType = await getEntityTypeById( - context.graphApi, - authentication, - { - entityTypeId, - temporalAxes: currentTimeInstantTemporalAxes, - }, - ); + const existingEntityType = await getEntityTypeById(context.graphApi, authentication, { + entityTypeId, + temporalAxes: currentTimeInstantTemporalAxes, + }); if (existingEntityType) { return existingEntityType; @@ -180,31 +168,23 @@ const seedFlowTestTypes = async () => { const webId = org.webId; - const valuePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Value", - description: "The value of something", - possibleValues: [{ primitiveDataType: "number" }], - }, - webId, + const valuePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Value", + description: "The value of something", + possibleValues: [{ primitiveDataType: "number" }], }, - ); + webId, + }); - const unitPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Unit", - description: "The name of a unit of something", - possibleValues: [{ primitiveDataType: "text" }], - }, - webId, + const unitPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Unit", + description: "The name of a unit of something", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webId, + }); const multiplierPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -212,8 +192,7 @@ const seedFlowTestTypes = async () => { { propertyTypeDefinition: { title: "Multiplier", - description: - 'The multiplier of something (e.g. "millions", "thousands", etc.)', + description: 'The multiplier of something (e.g. "millions", "thousands", etc.)', possibleValues: [{ primitiveDataType: "text" }], }, webId, @@ -233,8 +212,10 @@ const seedFlowTestTypes = async () => { }, ); - const marketCapitalizationPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const marketCapitalizationPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Market Capitalization", description: "The market capitalization of a company.", @@ -263,10 +244,13 @@ const seedFlowTestTypes = async () => { ], }, webId, - }); + }, + ); - const numberOfVotingRightsPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const numberOfVotingRightsPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Number of Voting Rights", description: @@ -289,10 +273,13 @@ const seedFlowTestTypes = async () => { ], }, webId, - }); + }, + ); - const ownershipPercentagePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const ownershipPercentagePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Ownership Percentage", description: @@ -300,7 +287,8 @@ const seedFlowTestTypes = async () => { possibleValues: [{ primitiveDataType: "number" }], }, webId, - }); + }, + ); const holdingTypePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -385,8 +373,10 @@ const seedFlowTestTypes = async () => { }, ); - const stockMarketConstituentEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { + const stockMarketConstituentEntityType = await createSystemEntityTypeIfNotExists( + context, + authentication, + { entityTypeDefinition: { title: "Stock Market Constituent", description: "A stock market constituent.", @@ -416,7 +406,8 @@ const seedFlowTestTypes = async () => { ], }, webId, - }); + }, + ); const _investmentFundEntityType = await createSystemEntityTypeIfNotExists( context, @@ -451,33 +442,29 @@ const seedFlowTestTypes = async () => { * 1. for identifying companies that are invested in an index but are not constituents of an index * 2. for identifying companies that a person worked at */ - const companyEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Company", - description: "A company", - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: investedInLinkEntityType, - destinationEntityTypes: [stockMarketConstituentEntityType], - }, - ], - }, - webId, + const companyEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Company", + description: "A company", + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: investedInLinkEntityType, + destinationEntityTypes: [stockMarketConstituentEntityType], + }, + ], }, - ); + webId, + }); const hashOrg = await getOrgByShortname(context, authentication, { shortname: "h", @@ -489,45 +476,37 @@ const seedFlowTestTypes = async () => { const hashWebId = hashOrg.webId; - const rolePropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Role", - description: "The name of a role performed by someone or something.", - possibleValues: [{ primitiveDataType: "text" }], - }, - webId: hashWebId, + const rolePropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Role", + description: "The name of a role performed by someone or something.", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webId: hashWebId, + }); - const workedAtLinkType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Worked At", - description: "Somewhere that someone or something worked at", - properties: [ - { - propertyType: systemPropertyTypes.appliesFrom.propertyTypeId, - required: false, - }, - { - propertyType: systemPropertyTypes.appliesUntil.propertyTypeId, - required: false, - }, - { - propertyType: rolePropertyType.schema.$id, - required: false, - }, - ], - }, - webId: hashWebId, + const workedAtLinkType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Worked At", + description: "Somewhere that someone or something worked at", + properties: [ + { + propertyType: systemPropertyTypes.appliesFrom.propertyTypeId, + required: false, + }, + { + propertyType: systemPropertyTypes.appliesUntil.propertyTypeId, + required: false, + }, + { + propertyType: rolePropertyType.schema.$id, + required: false, + }, + ], }, - ); + webId: hashWebId, + }); const linkedinUrlPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -542,15 +521,18 @@ const seedFlowTestTypes = async () => { }, ); - const googleScholarUrlPropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const googleScholarUrlPropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Google Scholar URL", description: "A URL to a Google Scholar profile", possibleValues: [{ primitiveDataType: "text" }], }, webId: hashWebId, - }); + }, + ); const twitterUrlPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -565,152 +547,134 @@ const seedFlowTestTypes = async () => { }, ); - const githubUrlPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "GitHub URL", - description: "A URL to a GitHub account", - possibleValues: [{ primitiveDataType: "text" }], - }, - webId: hashWebId, + const githubUrlPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "GitHub URL", + description: "A URL to a GitHub account", + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webId: hashWebId, + }); /** * This is a Person entity type for testing scraping of common fields one might want for a person. * This is a simplified representation – for employment, for example, you would probably actually * want separate entities for companies, and a link entity type for the employment relationship between them. */ - const personEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Person", - description: "A human person", - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - required: true, - }, - { - propertyType: systemPropertyTypes.email.propertyTypeId, - required: false, - array: true, - }, - { - propertyType: linkedinUrlPropertyType.schema.$id, - required: false, - }, - { - propertyType: googleScholarUrlPropertyType.schema.$id, - required: false, - }, - { - propertyType: twitterUrlPropertyType.schema.$id, - required: false, - }, - { - propertyType: githubUrlPropertyType.schema.$id, - required: false, - }, - ], - outgoingLinks: [ - { - linkEntityType: workedAtLinkType, - destinationEntityTypes: [companyEntityType], - }, - ], - }, - webId: hashWebId, + const personEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Person", + description: "A human person", + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + required: true, + }, + { + propertyType: systemPropertyTypes.email.propertyTypeId, + required: false, + array: true, + }, + { + propertyType: linkedinUrlPropertyType.schema.$id, + required: false, + }, + { + propertyType: googleScholarUrlPropertyType.schema.$id, + required: false, + }, + { + propertyType: twitterUrlPropertyType.schema.$id, + required: false, + }, + { + propertyType: githubUrlPropertyType.schema.$id, + required: false, + }, + ], + outgoingLinks: [ + { + linkEntityType: workedAtLinkType, + destinationEntityTypes: [companyEntityType], + }, + ], }, - ); + webId: hashWebId, + }); - const hasAuthorLinkEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - allOf: [blockProtocolEntityTypes.link.entityTypeId], - title: "Has Author", - description: "Something that has an author", - properties: [ - { - propertyType: systemPropertyTypes.appliesFrom.propertyTypeId, - required: false, - }, - { - propertyType: systemPropertyTypes.appliesUntil.propertyTypeId, - required: false, - }, - ], - }, - webId: hashWebId, + const hasAuthorLinkEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + allOf: [blockProtocolEntityTypes.link.entityTypeId], + title: "Has Author", + description: "Something that has an author", + properties: [ + { + propertyType: systemPropertyTypes.appliesFrom.propertyTypeId, + required: false, + }, + { + propertyType: systemPropertyTypes.appliesUntil.propertyTypeId, + required: false, + }, + ], }, - ); + webId: hashWebId, + }); - const _researchPaperType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Research Paper", - description: "A research paper", - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - required: true, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasAuthorLinkEntityType, - destinationEntityTypes: [personEntityType], - }, - ], - }, - webId: hashWebId, + const _researchPaperType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Research Paper", + description: "A research paper", + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + required: true, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasAuthorLinkEntityType, + destinationEntityTypes: [personEntityType], + }, + ], }, - ); + webId: hashWebId, + }); + + const _article = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Article", + description: "A article about something.", + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + }, + ], + outgoingLinks: [ + { + linkEntityType: hasAuthorLinkEntityType, + destinationEntityTypes: [personEntityType], + }, + ], + }, + webId: hashWebId, + }); - const _article = await createSystemEntityTypeIfNotExists( + const largeLanguageModelProviderEntityType = await createSystemEntityTypeIfNotExists( context, authentication, { - entityTypeDefinition: { - title: "Article", - description: "A article about something.", - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - }, - ], - outgoingLinks: [ - { - linkEntityType: hasAuthorLinkEntityType, - destinationEntityTypes: [personEntityType], - }, - ], - }, - webId: hashWebId, - }, - ); - - const largeLanguageModelProviderEntityType = - await createSystemEntityTypeIfNotExists(context, authentication, { entityTypeDefinition: { title: "Large Language Model Provider", description: "An entity that provides large language models.", @@ -726,7 +690,8 @@ const seedFlowTestTypes = async () => { ], }, webId: hashWebId, - }); + }, + ); const contextSizePropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -797,16 +762,18 @@ const seedFlowTestTypes = async () => { }, ); - const trainingDataCutoffDatePropertyType = - await createSystemPropertyTypeIfNotExists(context, authentication, { + const trainingDataCutoffDatePropertyType = await createSystemPropertyTypeIfNotExists( + context, + authentication, + { propertyTypeDefinition: { title: "Training Data Cutoff Date", - description: - "The date until which the training data was included for the model.", + description: "The date until which the training data was included for the model.", possibleValues: [{ dataTypeId: systemDataTypes.date.dataTypeId }], }, webId: hashWebId, - }); + }, + ); const providedByLinkEntityType = await createSystemEntityTypeIfNotExists( context, @@ -879,18 +846,14 @@ const seedFlowTestTypes = async () => { }, ); - const baseClockPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Base Clock", - description: "Base clock speed in GHz.", - possibleValues: [{ dataTypeId: systemDataTypes.gigahertz.dataTypeId }], - }, - webId: hashWebId, + const baseClockPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Base Clock", + description: "Base clock speed in GHz.", + possibleValues: [{ dataTypeId: systemDataTypes.gigahertz.dataTypeId }], }, - ); + webId: hashWebId, + }); const boostClockPropertyType = await createSystemPropertyTypeIfNotExists( context, @@ -957,181 +920,141 @@ const seedFlowTestTypes = async () => { }, ); - const widthPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Width", - description: "Width in mm.", - possibleValues: [ - { dataTypeId: systemDataTypes.millimeters.dataTypeId }, - ], - }, - webId: hashWebId, + const widthPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Width", + description: "Width in mm.", + possibleValues: [{ dataTypeId: systemDataTypes.millimeters.dataTypeId }], }, - ); + webId: hashWebId, + }); - const lengthPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Length", - description: "Length in mm.", - possibleValues: [ - { dataTypeId: systemDataTypes.millimeters.dataTypeId }, - ], - }, - webId: hashWebId, + const lengthPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Length", + description: "Length in mm.", + possibleValues: [{ dataTypeId: systemDataTypes.millimeters.dataTypeId }], }, - ); + webId: hashWebId, + }); - const powerDrawPropertyType = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Power Draw", - description: "Power draw in watts.", - possibleValues: [{ dataTypeId: systemDataTypes.watts.dataTypeId }], - }, - webId: hashWebId, + const powerDrawPropertyType = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Power Draw", + description: "Power draw in watts.", + possibleValues: [{ dataTypeId: systemDataTypes.watts.dataTypeId }], }, - ); + webId: hashWebId, + }); - const trainingStartDate = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Training Start Date", - description: "The date on which a thing's training began", - possibleValues: [{ dataTypeId: systemDataTypes.date.dataTypeId }], - }, - webId: hashWebId, + const trainingStartDate = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Training Start Date", + description: "The date on which a thing's training began", + possibleValues: [{ dataTypeId: systemDataTypes.date.dataTypeId }], }, - ); + webId: hashWebId, + }); - const trainingEndDate = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Training End Date", - description: "The date on which a thing's training ended", - possibleValues: [{ dataTypeId: systemDataTypes.date.dataTypeId }], - }, - webId: hashWebId, + const trainingEndDate = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Training End Date", + description: "The date on which a thing's training ended", + possibleValues: [{ dataTypeId: systemDataTypes.date.dataTypeId }], }, - ); + webId: hashWebId, + }); - const tokenOutputSpeed = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Token Output Speed", - description: - 'The rate at which an AI model is able to output tokens (generally, although not always, specified as "tokens per second")', - possibleValues: [{ primitiveDataType: "text" }], - }, - webId: hashWebId, + const tokenOutputSpeed = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Token Output Speed", + description: + 'The rate at which an AI model is able to output tokens (generally, although not always, specified as "tokens per second")', + possibleValues: [{ primitiveDataType: "text" }], }, - ); + webId: hashWebId, + }); - const contextWindow = await createSystemPropertyTypeIfNotExists( - context, - authentication, - { - propertyTypeDefinition: { - title: "Context Window", - description: - "The maximum number of tokens that an AI model can operate on, including both its inputs and outputs.", - possibleValues: [{ primitiveDataType: "number" }], - }, - webId: hashWebId, + const contextWindow = await createSystemPropertyTypeIfNotExists(context, authentication, { + propertyTypeDefinition: { + title: "Context Window", + description: + "The maximum number of tokens that an AI model can operate on, including both its inputs and outputs.", + possibleValues: [{ primitiveDataType: "number" }], }, - ); + webId: hashWebId, + }); - const _aiModelEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "AI Model", - description: - "An AI model is a program that has been trained on a set of data to recognize certain patterns and produce certain outputs (e.g. text, images, code, decisions) without further human intervention.", - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - required: true, - }, - { - propertyType: systemPropertyTypes.inputUnitCost.propertyTypeId, - }, - { - propertyType: systemPropertyTypes.outputUnitCost.propertyTypeId, - }, - { - propertyType: trainingStartDate, - }, - { - propertyType: trainingEndDate, - }, - { - propertyType: tokenOutputSpeed, - }, - { - propertyType: contextWindow, - }, - ], - }, - webId: hashWebId, + const _aiModelEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "AI Model", + description: + "An AI model is a program that has been trained on a set of data to recognize certain patterns and produce certain outputs (e.g. text, images, code, decisions) without further human intervention.", + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + required: true, + }, + { + propertyType: systemPropertyTypes.inputUnitCost.propertyTypeId, + }, + { + propertyType: systemPropertyTypes.outputUnitCost.propertyTypeId, + }, + { + propertyType: trainingStartDate, + }, + { + propertyType: trainingEndDate, + }, + { + propertyType: tokenOutputSpeed, + }, + { + propertyType: contextWindow, + }, + ], }, - ); + webId: hashWebId, + }); - const _graphicsCardEntityType = await createSystemEntityTypeIfNotExists( - context, - authentication, - { - entityTypeDefinition: { - title: "Graphics Card", - description: "A graphics card entity type.", - properties: [ - { - propertyType: blockProtocolPropertyTypes.name.propertyTypeId, - required: true, - }, - { - propertyType: blockProtocolPropertyTypes.description.propertyTypeId, - required: true, - }, - { - propertyType: nvidiaCUDACoresPropertyType.schema.$id, - required: false, - }, - { propertyType: baseClockPropertyType.schema.$id, required: false }, - { propertyType: boostClockPropertyType.schema.$id, required: false }, - { propertyType: memorySizePropertyType.schema.$id, required: false }, - { propertyType: memoryTypePropertyType.schema.$id, required: false }, - { - propertyType: rayTracingCoresPropertyType.schema.$id, - required: false, - }, - { propertyType: tensorCoresPropertyType.schema.$id, required: false }, - { propertyType: widthPropertyType.schema.$id, required: false }, - { propertyType: lengthPropertyType.schema.$id, required: false }, - { propertyType: powerDrawPropertyType.schema.$id, required: false }, - ], - }, - webId: hashWebId, + const _graphicsCardEntityType = await createSystemEntityTypeIfNotExists(context, authentication, { + entityTypeDefinition: { + title: "Graphics Card", + description: "A graphics card entity type.", + properties: [ + { + propertyType: blockProtocolPropertyTypes.name.propertyTypeId, + required: true, + }, + { + propertyType: blockProtocolPropertyTypes.description.propertyTypeId, + required: true, + }, + { + propertyType: nvidiaCUDACoresPropertyType.schema.$id, + required: false, + }, + { propertyType: baseClockPropertyType.schema.$id, required: false }, + { propertyType: boostClockPropertyType.schema.$id, required: false }, + { propertyType: memorySizePropertyType.schema.$id, required: false }, + { propertyType: memoryTypePropertyType.schema.$id, required: false }, + { + propertyType: rayTracingCoresPropertyType.schema.$id, + required: false, + }, + { propertyType: tensorCoresPropertyType.schema.$id, required: false }, + { propertyType: widthPropertyType.schema.$id, required: false }, + { propertyType: lengthPropertyType.schema.$id, required: false }, + { propertyType: powerDrawPropertyType.schema.$id, required: false }, + ], }, - ); + webId: hashWebId, + }); }; await seedFlowTestTypes(); diff --git a/apps/hash-api/src/seed-data/seed-pages.ts b/apps/hash-api/src/seed-data/seed-pages.ts index ba75b4d3353..1ec8816d9e5 100644 --- a/apps/hash-api/src/seed-data/seed-pages.ts +++ b/apps/hash-api/src/seed-data/seed-pages.ts @@ -1,7 +1,4 @@ -import { - createPage, - setPageParentPage, -} from "../graph/knowledge/system-types/page"; +import { createPage, setPageParentPage } from "../graph/knowledge/system-types/page"; import type { ImpureGraphContext } from "../graph/context-types"; import type { Page } from "../graph/knowledge/system-types/page"; @@ -48,13 +45,7 @@ export const seedPages = async ( prevFractionalIndex = newPage.fractionalIndex; if (pageDefinition.nestedPages) { - await seedPages( - authentication, - pageDefinition.nestedPages, - webId, - sharedParams, - newPage, - ); + await seedPages(authentication, pageDefinition.nestedPages, webId, sharedParams, newPage); } } }; diff --git a/apps/hash-api/src/seed-data/seed-users.ts b/apps/hash-api/src/seed-data/seed-users.ts index d2f993a5aad..23d64ccafbe 100644 --- a/apps/hash-api/src/seed-data/seed-users.ts +++ b/apps/hash-api/src/seed-data/seed-users.ts @@ -78,9 +78,7 @@ export const ensureUsersAreSeeded = async ({ } = usersToSeed[index]!; if (!(email && shortname && displayName)) { - logger.error( - `User entry at index ${index} is missing email, shortname or displayName!`, - ); + logger.error(`User entry at index ${index} is missing email, shortname or displayName!`); continue; } const maybeNewIdentity = await createKratosIdentity({ @@ -98,9 +96,7 @@ export const ensureUsersAreSeeded = async ({ // The user already exists on 409 CONFLICT, which is fine return null; } else { - logger.warn( - `Could not create seeded user identity, email = "${email}".`, - ); + logger.warn(`Could not create seeded user identity, email = "${email}".`); return Promise.reject(error); } }); diff --git a/apps/hash-api/src/shared/user-has-access-to-hash.ts b/apps/hash-api/src/shared/user-has-access-to-hash.ts index 4713f48bd60..232695148a9 100644 --- a/apps/hash-api/src/shared/user-has-access-to-hash.ts +++ b/apps/hash-api/src/shared/user-has-access-to-hash.ts @@ -1,23 +1,16 @@ -import { - getUserPendingInvitations, - type User, -} from "../graph/knowledge/system-types/user"; +import { getUserPendingInvitations, type User } from "../graph/knowledge/system-types/user"; import type { ImpureGraphContext } from "../graph/context-types"; import type { AuthenticationContext } from "@local/hash-graph-sdk/authentication-context"; const isArrayOfStrings = (value: unknown): value is string[] => { - return ( - Array.isArray(value) && value.every((item) => typeof item === "string") - ); + return Array.isArray(value) && value.every((item) => typeof item === "string"); }; let userEmailAllowList: string[] | undefined; if (process.env.USER_EMAIL_ALLOW_LIST) { try { - const uncheckedUserEmailAllowList = JSON.parse( - process.env.USER_EMAIL_ALLOW_LIST, - ) as unknown; + const uncheckedUserEmailAllowList = JSON.parse(process.env.USER_EMAIL_ALLOW_LIST) as unknown; if (!isArrayOfStrings(uncheckedUserEmailAllowList)) { throw new Error( @@ -67,19 +60,13 @@ export const userHasAccessToHash = async ( return { allowed: true }; } - const allowedEmails = user.emails.filter((email) => - userEmailAllowList.includes(email), - ); + const allowedEmails = user.emails.filter((email) => userEmailAllowList.includes(email)); if (allowedEmails.length > 0) { return { allowed: true, onlyForEmails: allowedEmails }; } - const pendingInvitations = await getUserPendingInvitations( - context, - authentication, - { user }, - ); + const pendingInvitations = await getUserPendingInvitations(context, authentication, { user }); return { allowed: pendingInvitations.length > 0 }; }; diff --git a/apps/hash-api/src/storage/index.ts b/apps/hash-api/src/storage/index.ts index 785552b5305..91a06f29d20 100644 --- a/apps/hash-api/src/storage/index.ts +++ b/apps/hash-api/src/storage/index.ts @@ -1,9 +1,6 @@ import { isEntityId, splitEntityId } from "@blockprotocol/type-system"; import { getAwsS3Config } from "@local/hash-backend-utils/aws-config"; -import { - isStorageType, - storageProviderLookup, -} from "@local/hash-backend-utils/file-storage"; +import { isStorageType, storageProviderLookup } from "@local/hash-backend-utils/file-storage"; import { AwsS3StorageProvider } from "@local/hash-backend-utils/file-storage/aws-s3-storage-provider"; import { queryEntities } from "@local/hash-graph-sdk/entity"; import { apiOrigin } from "@local/hash-isomorphic-utils/environment"; @@ -21,10 +18,7 @@ import { LocalFileSystemStorageProvider } from "./local-file-storage"; import type { ImpureGraphContext } from "../graph/context-types"; import type { Entity, EntityId } from "@blockprotocol/type-system"; -import type { - FileStorageProvider, - StorageType, -} from "@local/hash-backend-utils/file-storage"; +import type { FileStorageProvider, StorageType } from "@local/hash-backend-utils/file-storage"; import type { AuthenticationContext } from "@local/hash-graph-sdk/authentication-context"; import type { File as FileEntity } from "@local/hash-isomorphic-utils/system-types/shared"; import type { Express } from "express"; @@ -39,10 +33,7 @@ const DOWNLOAD_URL_CACHE_OFFSET_SECONDS = 60 * 60; type StorageProviderInitialiser = (app: Express) => FileStorageProvider; -const storageProviderInitialiserLookup: Record< - StorageType, - StorageProviderInitialiser -> = { +const storageProviderInitialiserLookup: Record = { AWS_S3: () => new AwsS3StorageProvider(getAwsS3Config()), LOCAL_FILE_SYSTEM: (app: Express) => new LocalFileSystemStorageProvider({ @@ -54,10 +45,7 @@ const storageProviderInitialiserLookup: Record< let uploadStorageProvider: StorageType = "LOCAL_FILE_SYSTEM"; -export const initialiseStorageProvider = ( - app: Express, - provider: StorageType, -) => { +export const initialiseStorageProvider = (app: Express, provider: StorageType) => { const initialiser = storageProviderInitialiserLookup[provider]; const newProvider = initialiser(app); @@ -97,57 +85,50 @@ const getFileEntity = async ( const { entityId, key, includeDrafts = false } = params; const [webId, entityUuid] = splitEntityId(entityId); - const { entities: fileEntityRevisions } = await queryEntities( - context, - authentication, - { - filter: { - all: [ - { - equal: [{ path: ["uuid"] }, { parameter: entityUuid }], - }, - { - equal: [{ path: ["webId"] }, { parameter: webId }], - }, - { - equal: [ - { - path: [ - "properties", - systemPropertyTypes.fileStorageKey.propertyTypeBaseUrl, - ], - }, - { parameter: key }, - ], - }, - ], - }, - temporalAxes: fullDecisionTimeAxis, - includeDrafts, - includePermissions: false, + const { entities: fileEntityRevisions } = await queryEntities(context, authentication, { + filter: { + all: [ + { + equal: [{ path: ["uuid"] }, { parameter: entityUuid }], + }, + { + equal: [{ path: ["webId"] }, { parameter: webId }], + }, + { + equal: [ + { + path: ["properties", systemPropertyTypes.fileStorageKey.propertyTypeBaseUrl], + }, + { parameter: key }, + ], + }, + ], }, - ); + temporalAxes: fullDecisionTimeAxis, + includeDrafts, + includePermissions: false, + }); - const latestFileEntityRevision = fileEntityRevisions.reduce< - Entity | undefined - >((previousLatestRevision, currentRevision) => { - if (!previousLatestRevision) { - return currentRevision; - } + const latestFileEntityRevision = fileEntityRevisions.reduce( + (previousLatestRevision, currentRevision) => { + if (!previousLatestRevision) { + return currentRevision; + } - const currentCreatedAt = new Date( - currentRevision.metadata.temporalVersioning.decisionTime.start.limit, - ); + const currentCreatedAt = new Date( + currentRevision.metadata.temporalVersioning.decisionTime.start.limit, + ); - const previousLatestRevisionCreatedAt = new Date( - previousLatestRevision.metadata.temporalVersioning.decisionTime.start - .limit, - ); + const previousLatestRevisionCreatedAt = new Date( + previousLatestRevision.metadata.temporalVersioning.decisionTime.start.limit, + ); - return previousLatestRevisionCreatedAt < currentCreatedAt - ? currentRevision - : previousLatestRevision; - }, fileEntityRevisions[0]); + return previousLatestRevisionCreatedAt < currentCreatedAt + ? currentRevision + : previousLatestRevision; + }, + fileEntityRevisions[0], + ); return latestFileEntityRevision; }; @@ -227,8 +208,7 @@ export const setupFileDownloadProxyHandler = (app: Express, cache: Keyv) => { ); if (!storageProviderName) { res.status(500).json({ - error: - "No storage provider listed on file entity – cannot retrieve file.", + error: "No storage provider listed on file entity – cannot retrieve file.", }); return; } @@ -268,9 +248,7 @@ export const setupFileDownloadProxyHandler = (app: Express, cache: Keyv) => { await cache.set( key, presignUrl, - (DOWNLOAD_URL_EXPIRATION_SECONDS - - DOWNLOAD_URL_CACHE_OFFSET_SECONDS) * - 1000, + (DOWNLOAD_URL_EXPIRATION_SECONDS - DOWNLOAD_URL_CACHE_OFFSET_SECONDS) * 1000, ); } catch (error) { logger.warn( diff --git a/apps/hash-api/src/storage/local-file-storage.ts b/apps/hash-api/src/storage/local-file-storage.ts index bd21447cdf1..3a80737c4a0 100644 --- a/apps/hash-api/src/storage/local-file-storage.ts +++ b/apps/hash-api/src/storage/local-file-storage.ts @@ -42,11 +42,7 @@ export class LocalFileSystemStorageProvider implements FileStorageProvider { private fileUploadPath: string; private apiOrigin: string; - constructor({ - app, - fileUploadPath, - apiOrigin, - }: LocalFileSystemStorageProviderConstructorArgs) { + constructor({ app, fileUploadPath, apiOrigin }: LocalFileSystemStorageProviderConstructorArgs) { this.fileUploadPath = path.join(appRoot.path, fileUploadPath); this.apiOrigin = apiOrigin; if (!fs.existsSync(this.fileUploadPath)) { @@ -67,15 +63,13 @@ export class LocalFileSystemStorageProvider implements FileStorageProvider { "https://hash.ai/@h/types/property-type/file-storage-key/": { value: key, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, "https://hash.ai/@h/types/property-type/file-storage-provider/": { value: this.storageType, metadata: { - dataTypeId: - "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", + dataTypeId: "https://blockprotocol.org/@blockprotocol/types/data-type/text/v/1", }, }, } satisfies Pick< @@ -88,8 +82,7 @@ export class LocalFileSystemStorageProvider implements FileStorageProvider { } async presignDownload(params: PresignedDownloadRequest): Promise { - return new URL(path.join(DOWNLOAD_BASE_URL, params.key), this.apiOrigin) - .href as Url; + return new URL(path.join(DOWNLOAD_BASE_URL, params.key), this.apiOrigin).href as Url; } getFileEntityStorageKey({ @@ -172,10 +165,7 @@ export class LocalFileSystemStorageProvider implements FileStorageProvider { return; } - const fileWritePath = path.join( - this.fileUploadPath, - path.normalize(req.query.key), - ); + const fileWritePath = path.join(this.fileUploadPath, path.normalize(req.query.key)); if (!fileWritePath.startsWith(this.fileUploadPath)) { res.status(400).send("Invalid key query parameter"); diff --git a/apps/hash-api/src/telemetry/rudderstack.ts b/apps/hash-api/src/telemetry/rudderstack.ts index 363c788fa8f..6d231aa5ac4 100644 --- a/apps/hash-api/src/telemetry/rudderstack.ts +++ b/apps/hash-api/src/telemetry/rudderstack.ts @@ -2,8 +2,7 @@ import RudderAnalytics from "@rudderstack/rudder-sdk-node"; import { frontendDomain } from "@local/hash-isomorphic-utils/environment"; -const RUDDERSTACK_KEY = - process.env.HASH_API_RUDDERSTACK_KEY || "2SKw8Q5jz5g08LNKpk0Ag82N7HL"; +const RUDDERSTACK_KEY = process.env.HASH_API_RUDDERSTACK_KEY || "2SKw8Q5jz5g08LNKpk0Ag82N7HL"; export class Telemetry { private static rudder_client: RudderAnalytics | undefined | null = undefined; diff --git a/apps/hash-api/src/telemetry/snowplow-setup.ts b/apps/hash-api/src/telemetry/snowplow-setup.ts index f1777ae1474..8bfb4a316af 100644 --- a/apps/hash-api/src/telemetry/snowplow-setup.ts +++ b/apps/hash-api/src/telemetry/snowplow-setup.ts @@ -1,8 +1,4 @@ -import { - buildStructEvent, - newTracker, - type Tracker, -} from "@snowplow/node-tracker"; +import { buildStructEvent, newTracker, type Tracker } from "@snowplow/node-tracker"; import { getRequiredEnv } from "@local/hash-backend-utils/environment"; @@ -11,8 +7,7 @@ import { getRequiredEnv } from "@local/hash-backend-utils/environment"; * This tracking function simply sends an event when the platform starts to record usage metrics. */ export const setupTelemetry = async (): Promise => { - const protocol = - process.env.HASH_TELEMETRY_HTTPS === "true" ? "https" : "http"; + const protocol = process.env.HASH_TELEMETRY_HTTPS === "true" ? "https" : "http"; const tracker = newTracker( { diff --git a/apps/hash-api/src/util.test.ts b/apps/hash-api/src/util.test.ts index 6d0a9039ba7..25ff2966c6d 100644 --- a/apps/hash-api/src/util.test.ts +++ b/apps/hash-api/src/util.test.ts @@ -1,11 +1,6 @@ import { describe, expect, it } from "vitest"; -import { - intersection, - linkedTreeFlatten, - topologicalSort, - treeFromParentReferences, -} from "./util"; +import { intersection, linkedTreeFlatten, topologicalSort, treeFromParentReferences } from "./util"; describe("topological sort", () => { it("can do topological sort", () => { @@ -223,9 +218,9 @@ describe("restructure flat list to tree", () => { { id: "5" }, ] as Element[]; - expect(() => - treeFromParentReferences(test1, "id", "ref", "children"), - ).toThrow("graph is not acyclic"); + expect(() => treeFromParentReferences(test1, "id", "ref", "children")).toThrow( + "graph is not acyclic", + ); }); it("can rebuild tree with invalid refs", () => { diff --git a/apps/hash-api/src/util.ts b/apps/hash-api/src/util.ts index 85820cb9ec0..032b4156887 100644 --- a/apps/hash-api/src/util.ts +++ b/apps/hash-api/src/util.ts @@ -55,9 +55,7 @@ export const linkedTreeFlatten = < // The return value will be a list of the Outer type optionally augmented with metadata and a parentid type ResultWithMeta = Omit; - const queue: AugmentedOuter[][] = [ - [{ parentIndex: -1, currentIndex: 0, ...graph }], - ]; + const queue: AugmentedOuter[][] = [[{ parentIndex: -1, currentIndex: 0, ...graph }]]; const result: ResultWithMeta[] = []; let index = 1; diff --git a/apps/hash-api/views/consent.hbs b/apps/hash-api/views/consent.hbs index 390fcc19f10..d6be472d49a 100644 --- a/apps/hash-api/views/consent.hbs +++ b/apps/hash-api/views/consent.hbs @@ -12,35 +12,17 @@ {{#each requested_scope as |scope|}} {{/each}} - + diff --git a/apps/hash-external-services/docker-compose.dev.yml b/apps/hash-external-services/docker-compose.dev.yml index e4ef3272f23..00a4af6d3d0 100644 --- a/apps/hash-external-services/docker-compose.dev.yml +++ b/apps/hash-external-services/docker-compose.dev.yml @@ -211,8 +211,7 @@ services: - GF_AUTH_DISABLE_LOGIN_FORM=true restart: unless-stopped healthcheck: - test: - ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api/health"] + test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api/health"] interval: 2s timeout: 2s retries: 10 diff --git a/apps/hash-external-services/docker-compose.prod.yml b/apps/hash-external-services/docker-compose.prod.yml index 21cc89b6d24..7fdcc759ba0 100644 --- a/apps/hash-external-services/docker-compose.prod.yml +++ b/apps/hash-external-services/docker-compose.prod.yml @@ -133,14 +133,7 @@ services: RUST_BACKTRACE: 0 healthcheck: test: - [ - "CMD", - "/hash-graph", - "server", - "--healthcheck", - "--api-port", - "${HASH_GRAPH_HTTP_PORT}", - ] + ["CMD", "/hash-graph", "server", "--healthcheck", "--api-port", "${HASH_GRAPH_HTTP_PORT}"] interval: 2s timeout: 2s retries: 10 diff --git a/apps/hash-external-services/docker-compose.test.yml b/apps/hash-external-services/docker-compose.test.yml index 55fa2d637e4..1a38e3a7aa4 100644 --- a/apps/hash-external-services/docker-compose.test.yml +++ b/apps/hash-external-services/docker-compose.test.yml @@ -48,11 +48,7 @@ services: condition: on-failure healthcheck: # Port 14269 is the Jaeger admin endpoint - test: - [ - "CMD-SHELL", - "wget --no-verbose --tries=1 --spider http://localhost:14269 || exit 1", - ] + test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:14269 || exit 1"] interval: 2s timeout: 2s retries: 10 diff --git a/apps/hash-external-services/docker-compose.yml b/apps/hash-external-services/docker-compose.yml index 9da1bf8ba10..d4d37c769d9 100644 --- a/apps/hash-external-services/docker-compose.yml +++ b/apps/hash-external-services/docker-compose.yml @@ -32,8 +32,7 @@ services: - ./postgres/init-user-db.sh:/docker-entrypoint-initdb.d/init-user-db.sh:ro shm_size: 1GB healthcheck: - test: - ["CMD", "pg_isready", "-q", "-h", "postgres", "-U", "${POSTGRES_USER}"] + test: ["CMD", "pg_isready", "-q", "-h", "postgres", "-U", "${POSTGRES_USER}"] interval: 2s timeout: 2s retries: 5 @@ -213,16 +212,7 @@ services: condition: service_completed_successfully healthcheck: test: - [ - "CMD", - "temporal", - "workflow", - "list", - "--namespace", - "HASH", - "--address", - "temporal:7233", - ] + ["CMD", "temporal", "workflow", "list", "--namespace", "HASH", "--address", "temporal:7233"] interval: 10s timeout: 2s retries: 10 diff --git a/apps/hash-frontend/buildstamp.js b/apps/hash-frontend/buildstamp.js index cf8c498be28..be4cc8b4b7e 100644 --- a/apps/hash-frontend/buildstamp.js +++ b/apps/hash-frontend/buildstamp.js @@ -1,6 +1,5 @@ const branch = process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF ?? "local-dev"; -const identifier = - process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA ?? new Date().toISOString(); +const identifier = process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA ?? new Date().toISOString(); const buildStamp = `commit-${identifier}-${branch.replace(/\//g, "-")}`; export { buildStamp }; diff --git a/apps/hash-frontend/codegen.config.ts b/apps/hash-frontend/codegen.config.ts index fa4dec83221..a19e2d368ef 100644 --- a/apps/hash-frontend/codegen.config.ts +++ b/apps/hash-frontend/codegen.config.ts @@ -4,8 +4,7 @@ import type { CodegenConfig } from "@graphql-codegen/cli"; const config: CodegenConfig = { overwrite: true, - schema: - "../../libs/@local/hash-isomorphic-utils/src/graphql/type-defs/**/*.ts", + schema: "../../libs/@local/hash-isomorphic-utils/src/graphql/type-defs/**/*.ts", generates: { "./src/graphql/fragment-types.gen.json": { plugins: ["fragment-matcher"], diff --git a/apps/hash-frontend/eslint.config.js b/apps/hash-frontend/eslint.config.js index 946fd9b1ba5..1f7dc4cdf85 100644 --- a/apps/hash-frontend/eslint.config.js +++ b/apps/hash-frontend/eslint.config.js @@ -1,8 +1,4 @@ -import { - defineConfig, - createBase, - disableRules, -} from "@local/eslint/deprecated"; +import { defineConfig, createBase, disableRules } from "@local/eslint/deprecated"; export default [ ...createBase(import.meta.dirname), @@ -52,8 +48,7 @@ export default [ { name: "notistack", importNames: ["useSnackbar"], - message: - "Please use the custom src/components/hooks/useSnackbar hook instead.", + message: "Please use the custom src/components/hooks/useSnackbar hook instead.", }, { name: "@hashintel/design-system", diff --git a/apps/hash-frontend/instrumentation-client.ts b/apps/hash-frontend/instrumentation-client.ts index 982242cc992..2eeb26c08c0 100644 --- a/apps/hash-frontend/instrumentation-client.ts +++ b/apps/hash-frontend/instrumentation-client.ts @@ -27,9 +27,7 @@ Sentry.init({ ], release: buildStamp, replaysOnErrorSampleRate: 1, - replaysSessionSampleRate: parseFloat( - SENTRY_REPLAYS_SESSION_SAMPLE_RATE ?? "0", - ), + replaysSessionSampleRate: parseFloat(SENTRY_REPLAYS_SESSION_SAMPLE_RATE ?? "0"), sendDefaultPii: true, tracePropagationTargets: ["localhost", /^https:\/\/(?:.*\.)?hash\.ai/], tracesSampleRate: isProduction ? 1.0 : 0, diff --git a/apps/hash-frontend/next.config.js b/apps/hash-frontend/next.config.js index 19ce65f5d5c..cafdaf3a2c1 100644 --- a/apps/hash-frontend/next.config.js +++ b/apps/hash-frontend/next.config.js @@ -35,30 +35,25 @@ const sentryWebpackPluginOptions = { // NOTE THAT any environment variable which is _missing_ will be converted to the string 'undefined' if no fallback is set // Show the worker cost in the UI. Always enabled for admins -process.env.NEXT_PUBLIC_SHOW_WORKER_COST = - process.env.SHOW_WORKER_COST ?? "false"; +process.env.NEXT_PUBLIC_SHOW_WORKER_COST = process.env.SHOW_WORKER_COST ?? "false"; // This allows the frontend to generate the graph type IDs in the browser process.env.NEXT_PUBLIC_FRONTEND_URL = process.env.FRONTEND_URL; // The API origin -process.env.NEXT_PUBLIC_API_ORIGIN = - process.env.API_ORIGIN ?? "http://localhost:5001"; +process.env.NEXT_PUBLIC_API_ORIGIN = process.env.API_ORIGIN ?? "http://localhost:5001"; process.env.NEXT_PUBLIC_SENTRY_DSN = process.env.SENTRY_DSN ?? ""; process.env.NEXT_PUBLIC_ENVIRONMENT = process.env.ENVIRONMENT ?? ""; -process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT = - process.env.SENTRY_ENVIRONMENT ?? ""; +process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT = process.env.SENTRY_ENVIRONMENT ?? ""; process.env.NEXT_PUBLIC_SENTRY_REPLAY_SESSION_SAMPLE_RATE = process.env.SENTRY_REPLAY_SESSION_SAMPLE_RATE ?? "1"; -process.env.NEXT_PUBLIC_NOTIFICATION_POLL_INTERVAL = - process.env.NOTIFICATION_POLL_INTERVAL ?? ""; +process.env.NEXT_PUBLIC_NOTIFICATION_POLL_INTERVAL = process.env.NOTIFICATION_POLL_INTERVAL ?? ""; process.env.NEXT_PUBLIC_SELF_HOSTED_HASH = process.env.SELF_HOSTED_HASH ?? ""; -process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_ID = - process.env.GOOGLE_OAUTH_CLIENT_ID ?? ""; +process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CLIENT_ID = process.env.GOOGLE_OAUTH_CLIENT_ID ?? ""; const apiUrl = process.env.NEXT_PUBLIC_API_ORIGIN ?? "http://localhost:5001"; diff --git a/apps/hash-frontend/src/blocks/on-block-loaded.tsx b/apps/hash-frontend/src/blocks/on-block-loaded.tsx index 6edf7f5770d..58161a2ceb6 100644 --- a/apps/hash-frontend/src/blocks/on-block-loaded.tsx +++ b/apps/hash-frontend/src/blocks/on-block-loaded.tsx @@ -1,11 +1,4 @@ -import { - createContext, - useCallback, - useContext, - useMemo, - useRef, - useState, -} from "react"; +import { createContext, useCallback, useContext, useMemo, useRef, useState } from "react"; import { getBlockDomId } from "../shared/get-block-dom-id"; @@ -25,21 +18,18 @@ type BlockLoadedProviderProps = { routeHash?: string; }; -export const BlockLoadedProvider: FunctionComponent< - BlockLoadedProviderProps -> = ({ routeHash, children }) => { +export const BlockLoadedProvider: FunctionComponent = ({ + routeHash, + children, +}) => { const scrollingComplete = useRef(false); - const scrollFrameRequestIdRef = useRef | null>(null); + const scrollFrameRequestIdRef = useRef | null>(null); /** * The initial value is `routeHash`, so when the page is first open, the block which has its id in URL is highlighted * `highlightedBlockId` will be used when block context menus are open to indicate which block is being edited */ - const [highlightedBlockId, setHighlightedBlockId] = useState< - string | undefined - >(routeHash); + const [highlightedBlockId, setHighlightedBlockId] = useState(routeHash); const onBlockLoaded = useCallback( (blockEntityId: string) => { @@ -59,14 +49,9 @@ export const BlockLoadedProvider: FunctionComponent< } } - if ( - routeHash === getBlockDomId(blockEntityId) && - !scrollingComplete.current - ) { + if (routeHash === getBlockDomId(blockEntityId) && !scrollingComplete.current) { clearScrollInterval(); - scrollFrameRequestIdRef.current = requestAnimationFrame(() => - frame(routeHash), - ); + scrollFrameRequestIdRef.current = requestAnimationFrame(() => frame(routeHash)); } }, [routeHash], @@ -77,11 +62,7 @@ export const BlockLoadedProvider: FunctionComponent< [highlightedBlockId, setHighlightedBlockId, onBlockLoaded], ); - return ( - - {children} - - ); + return {children}; }; export const useBlockLoadedContext = () => { diff --git a/apps/hash-frontend/src/blocks/use-fetch-block-subgraph.ts b/apps/hash-frontend/src/blocks/use-fetch-block-subgraph.ts index c8df6f7ef41..29c4770098f 100644 --- a/apps/hash-frontend/src/blocks/use-fetch-block-subgraph.ts +++ b/apps/hash-frontend/src/blocks/use-fetch-block-subgraph.ts @@ -2,10 +2,7 @@ import { useLazyQuery } from "@apollo/client"; import { useCallback } from "react"; import { currentTimestamp, splitEntityId } from "@blockprotocol/type-system"; -import { - deserializeQueryEntitySubgraphResponse, - HashEntity, -} from "@local/hash-graph-sdk/entity"; +import { deserializeQueryEntitySubgraphResponse, HashEntity } from "@local/hash-graph-sdk/entity"; import { almostFullOntologyResolveDepths, currentTimeInstantTemporalAxes, @@ -17,11 +14,7 @@ import type { QueryEntitySubgraphQueryVariables, SubgraphAndPermissions as SubgraphAndPermissionsGQL, } from "../graphql/api-types.gen"; -import type { - EntityRootType, - KnowledgeGraphVertices, - Subgraph, -} from "@blockprotocol/graph"; +import type { EntityRootType, KnowledgeGraphVertices, Subgraph } from "@blockprotocol/graph"; import type { ActorEntityUuid, EntityEditionId, @@ -202,15 +195,11 @@ export const useFetchBlockSubgraph = (): (( .then(({ data, error }) => { if (!data) { throw new Error( - `Could not get entity ${blockEntityId}: ${ - error ? error.message : "unknown error" - }`, + `Could not get entity ${blockEntityId}: ${error ? error.message : "unknown error"}`, ); } - const response = deserializeQueryEntitySubgraphResponse( - data.queryEntitySubgraph, - ); + const response = deserializeQueryEntitySubgraphResponse(data.queryEntitySubgraph); return { subgraph: response.subgraph, diff --git a/apps/hash-frontend/src/blocks/user-blocks.tsx b/apps/hash-frontend/src/blocks/user-blocks.tsx index e00cd9a9b3b..2cbc3090177 100644 --- a/apps/hash-frontend/src/blocks/user-blocks.tsx +++ b/apps/hash-frontend/src/blocks/user-blocks.tsx @@ -1,10 +1,4 @@ -import { - createContext, - useCallback, - useContext, - useEffect, - useMemo, -} from "react"; +import { createContext, useCallback, useContext, useEffect, useMemo } from "react"; import { fetchBlock } from "@local/hash-isomorphic-utils/blocks"; @@ -13,12 +7,7 @@ import { useGetBlockProtocolBlocks } from "../components/hooks/use-get-block-pro import type { EntityType } from "@blockprotocol/type-system"; import type { ComponentIdHashBlockMap } from "@local/hash-isomorphic-utils/blocks"; -import type { - Dispatch, - FunctionComponent, - ReactNode, - SetStateAction, -} from "react"; +import type { Dispatch, FunctionComponent, ReactNode, SetStateAction } from "react"; interface UserBlocksContextState { value: ComponentIdHashBlockMap; @@ -139,11 +128,7 @@ export const UserBlocksProvider: FunctionComponent<{ [value, setValue, error], ); - return ( - - {children} - - ); + return {children}; }; export const useUserBlocks = () => { diff --git a/apps/hash-frontend/src/components/block-loader/block-loader.tsx b/apps/hash-frontend/src/components/block-loader/block-loader.tsx index a785b763946..1d4e6a36807 100644 --- a/apps/hash-frontend/src/components/block-loader/block-loader.tsx +++ b/apps/hash-frontend/src/components/block-loader/block-loader.tsx @@ -8,10 +8,7 @@ import { useState, } from "react"; -import { - extractWebIdFromEntityId, - isEntityId, -} from "@blockprotocol/type-system"; +import { extractWebIdFromEntityId, isEntityId } from "@blockprotocol/type-system"; import { typedEntries } from "@local/advanced-types/typed-entries"; import { HashEntity } from "@local/hash-graph-sdk/entity"; import { @@ -98,9 +95,7 @@ const rewrittenPropertiesForTextualContent = (properties: PropertyObject) => { return { ...properties, [textualContentPropertyTypeBaseUrl]: textTokens - .map((token) => - "text" in token ? token.text : "hardBreak" in token ? "\n" : "", - ) + .map((token) => ("text" in token ? token.text : "hardBreak" in token ? "\n" : "")) .join(""), }; }; @@ -128,17 +123,11 @@ export const BlockLoader: FunctionComponent = ({ const { activeWorkspaceWebId } = useContext(WorkspaceContext); const { queryEntities } = useBlockProtocolQueryEntities(); - const { createEntity } = useBlockProtocolCreateEntity( - activeWorkspaceWebId ?? null, - readonly, - ); + const { createEntity } = useBlockProtocolCreateEntity(activeWorkspaceWebId ?? null, readonly); const { archiveEntity: deleteEntity } = useBlockProtocolArchiveEntity(); const { getEntity } = useBlockProtocolGetEntity(); const { updateEntity } = useBlockProtocolUpdateEntity(); - const { uploadFile } = useBlockProtocolFileUpload( - activeWorkspaceWebId, - readonly, - ); + const { uploadFile } = useBlockProtocolFileUpload(activeWorkspaceWebId, readonly); const { setBlockSubgraph, @@ -181,9 +170,7 @@ export const BlockLoader: FunctionComponent = ({ * The traversal depths will not be accurate, because the actual traversal was rooted at the block collection. * This data is only used briefly – we fetch the block's subgraph from the API further on this effect. */ - const latestEditionId = Object.keys(entityEditionMap) - .toSorted() - .at(-1)!; + const latestEditionId = Object.keys(entityEditionMap).toSorted().at(-1)!; subgraphToRewrite = { ...blockCollectionSubgraph, roots: [ @@ -205,8 +192,7 @@ export const BlockLoader: FunctionComponent = ({ * The block subgraph should have a single root: the block entity. We'll default to the API-provided one, * but might need to replace it if there's a later version in the entity store, since the version is part of the root identifier */ - let roots: Subgraph>["roots"] = - subgraphToRewrite.roots; + let roots: Subgraph>["roots"] = subgraphToRewrite.roots; const newVertices: Subgraph>["vertices"] = {}; @@ -251,14 +237,13 @@ export const BlockLoader: FunctionComponent = ({ entityInStore?.metadata.temporalVersioning.decisionTime.start.limit; const draftEntityIsNewer = - draftEntityEditionTimestamp && - latestSubgraphEditionTimestamp < draftEntityEditionTimestamp; + draftEntityEditionTimestamp && latestSubgraphEditionTimestamp < draftEntityEditionTimestamp; if (!entityInStore || !draftEntityIsNewer) { if (isBlockEntity) { - const entityVertex = ( - entityOrTypeEditionMap as KnowledgeGraphEditionMap - )[latestSubgraphEditionTimestamp]; + const entityVertex = (entityOrTypeEditionMap as KnowledgeGraphEditionMap)[ + latestSubgraphEditionTimestamp + ]; if (!entityVertex) { throw new Error( @@ -274,12 +259,9 @@ export const BlockLoader: FunctionComponent = ({ inner: new HashEntity({ ...entityVertex.inner.toJSON(), properties: rewrittenPropertiesForTextualContent( - ( - entityOrTypeEditionMap as Record< - EntityRevisionId, - EntityVertex - > - )[latestSubgraphEditionTimestamp]!.inner.properties, + (entityOrTypeEditionMap as Record)[ + latestSubgraphEditionTimestamp + ]!.inner.properties, ), }), }, @@ -299,18 +281,14 @@ export const BlockLoader: FunctionComponent = ({ inner: new HashEntity({ metadata: { recordId: entityInStore.metadata.recordId as EntityRecordId, - entityTypeIds: [ - entityInStore.metadata.entityTypeId, - ] as VersionedUrl[], + entityTypeIds: [entityInStore.metadata.entityTypeId] as VersionedUrl[], temporalVersioning: entityInStore.metadata.temporalVersioning, archived: false, provenance: { createdAtDecisionTime: - entityInStore.metadata.temporalVersioning.decisionTime.start - .limit, + entityInStore.metadata.temporalVersioning.decisionTime.start.limit, createdAtTransactionTime: - entityInStore.metadata.temporalVersioning.transactionTime - .start.limit, + entityInStore.metadata.temporalVersioning.transactionTime.start.limit, createdById: extractWebIdFromEntityId( entityInStore.metadata.recordId.entityId as EntityId, ), @@ -327,9 +305,7 @@ export const BlockLoader: FunctionComponent = ({ }, properties: isBlockEntity ? entityInStore.properties - : rewrittenPropertiesForTextualContent( - entityInStore.properties, - ), + : rewrittenPropertiesForTextualContent(entityInStore.properties), linkData: entityInStore.linkData, }), } satisfies EntityVertex, @@ -354,12 +330,7 @@ export const BlockLoader: FunctionComponent = ({ roots, vertices: newVertices, }; - }, [ - blockCollectionSubgraph, - blockEntityId, - entityStore, - possiblyStaleSubgraph, - ]); + }, [blockCollectionSubgraph, blockEntityId, entityStore, possiblyStaleSubgraph]); /** * If we are able to derive the `blockSubgraph` without the value from the context, @@ -371,8 +342,7 @@ export const BlockLoader: FunctionComponent = ({ const lastFetchedBlockEntityId = useRef(null); - const [fetchingBlockSubgraph, setFetchingBlockSubgraph] = - useState(false); + const [fetchingBlockSubgraph, setFetchingBlockSubgraph] = useState(false); /** * Fetch the block's subgraph and permissions on load and when the block's entityId changes @@ -394,15 +364,13 @@ export const BlockLoader: FunctionComponent = ({ * When blocks are created mid-session, we cannot rely on their entity or permissions being in the block collection subgraph. * If we don't yet have a blockEntityId, fetchBlockSubgraph will provide a default. */ - void fetchBlockSubgraph( - blockEntityTypeIds, - blockEntityId, - fallbackBlockProperties, - ).then((newBlockSubgraph) => { - setBlockSubgraph(newBlockSubgraph.subgraph); - setUserPermissions(newBlockSubgraph.userPermissionsOnEntities); - setFetchingBlockSubgraph(false); - }); + void fetchBlockSubgraph(blockEntityTypeIds, blockEntityId, fallbackBlockProperties).then( + (newBlockSubgraph) => { + setBlockSubgraph(newBlockSubgraph.subgraph); + setUserPermissions(newBlockSubgraph.userPermissionsOnEntities); + setFetchingBlockSubgraph(false); + }, + ); }, [ fetchingBlockSubgraph, blockEntityId, @@ -415,20 +383,11 @@ export const BlockLoader: FunctionComponent = ({ ]); const refetchSubgraph = useCallback(async () => { - const newBlockSubgraph = await fetchBlockSubgraph( - blockEntityTypeIds, - blockEntityId, - ); + const newBlockSubgraph = await fetchBlockSubgraph(blockEntityTypeIds, blockEntityId); setBlockSubgraph(newBlockSubgraph.subgraph); setUserPermissions(newBlockSubgraph.userPermissionsOnEntities); - }, [ - blockEntityId, - blockEntityTypeIds, - fetchBlockSubgraph, - setBlockSubgraph, - setUserPermissions, - ]); + }, [blockEntityId, blockEntityTypeIds, fetchBlockSubgraph, setBlockSubgraph, setUserPermissions]); const functions = useMemo( () => ({ @@ -438,35 +397,23 @@ export const BlockLoader: FunctionComponent = ({ * @see https://linear.app/hash/issue/H-2996 */ getEmbedBlock: fetchEmbedCode, - createEntity: async ( - ...args: Parameters - ) => { - const res = await createEntity( - args[0] as Parameters[0], - ); + createEntity: async (...args: Parameters) => { + const res = await createEntity(args[0] as Parameters[0]); await refetchSubgraph(); return res; }, - deleteEntity: async ( - ...args: Parameters - ) => { - const res = await deleteEntity( - args[0] as Parameters[0], - ); + deleteEntity: async (...args: Parameters) => { + const res = await deleteEntity(args[0] as Parameters[0]); await refetchSubgraph(); return res; }, getEntity, - uploadFile: async ( - ...args: Parameters - ) => { - const res = await uploadFile( - args[0] as Parameters[0], - ); + uploadFile: async (...args: Parameters) => { + const res = await uploadFile(args[0] as Parameters[0]); await refetchSubgraph(); @@ -479,9 +426,7 @@ export const BlockLoader: FunctionComponent = ({ return { data: null }; }, updateEntity: async (...args) => { - const res = await updateEntity( - args[0] as Parameters[0], - ); + const res = await updateEntity(args[0] as Parameters[0]); await refetchSubgraph(); @@ -528,9 +473,7 @@ export const BlockLoader: FunctionComponent = ({ // ); // } - const graphProperties = useMemo | null>( + const graphProperties = useMemo | null>( () => blockSubgraph ? { @@ -545,8 +488,7 @@ export const BlockLoader: FunctionComponent = ({ userPermissions?.[blockEntityId] && !userPermissions[blockEntityId].update ), - blockEntitySubgraph: - blockSubgraph as unknown as Subgraph, + blockEntitySubgraph: blockSubgraph as unknown as Subgraph, } : null, [blockEntityId, blockSubgraph, readonly, userPermissions], diff --git a/apps/hash-frontend/src/components/block-loader/fetch-embed-code.ts b/apps/hash-frontend/src/components/block-loader/fetch-embed-code.ts index d776ff9fa83..ccb96924f15 100644 --- a/apps/hash-frontend/src/components/block-loader/fetch-embed-code.ts +++ b/apps/hash-frontend/src/components/block-loader/fetch-embed-code.ts @@ -2,10 +2,7 @@ import { apiGraphQLEndpoint } from "@local/hash-isomorphic-utils/environment"; import type { JsonObject } from "@blockprotocol/core"; -export type FetchEmbedCodeFn = ( - url: string, - type?: string, -) => Promise; +export type FetchEmbedCodeFn = (url: string, type?: string) => Promise; export const fetchEmbedCode: FetchEmbedCodeFn = (url, type?) => { return fetch(apiGraphQLEndpoint, { diff --git a/apps/hash-frontend/src/components/confirmation-alert.tsx b/apps/hash-frontend/src/components/confirmation-alert.tsx index a563650c18e..616d88a99a7 100644 --- a/apps/hash-frontend/src/components/confirmation-alert.tsx +++ b/apps/hash-frontend/src/components/confirmation-alert.tsx @@ -35,9 +35,7 @@ export const ConfirmationAlert: FunctionComponent = ({ > {title} - - {children} - + {children} diff --git a/apps/hash-frontend/src/components/dropdowns/version-dropdown.tsx b/apps/hash-frontend/src/components/dropdowns/version-dropdown.tsx index 38fc68159ae..2a32535f35f 100644 --- a/apps/hash-frontend/src/components/dropdowns/version-dropdown.tsx +++ b/apps/hash-frontend/src/components/dropdowns/version-dropdown.tsx @@ -29,9 +29,7 @@ export const VersionDropdown: FunctionComponent = ({ width: 200, borderRadius: "4px", }} - onChange={(event: ChangeEvent) => - onChange(event.target.value) - } + onChange={(event: ChangeEvent) => onChange(event.target.value)} value={value} > {versions.map((version) => ( diff --git a/apps/hash-frontend/src/components/error-block/error-block.tsx b/apps/hash-frontend/src/components/error-block/error-block.tsx index 4b8c7c4cc7c..1434cea61f8 100644 --- a/apps/hash-frontend/src/components/error-block/error-block.tsx +++ b/apps/hash-frontend/src/components/error-block/error-block.tsx @@ -11,10 +11,7 @@ export interface ErrorBlockProps extends FallbackRenderProps { onRetry: () => void; } -export const ErrorBlock: FunctionComponent = ({ - error, - onRetry, -}) => ( +export const ErrorBlock: FunctionComponent = ({ error, onRetry }) => (
= ({ ( ); return ( -
+
{label && (
); diff --git a/apps/hash-frontend/src/components/forms/tags-input.tsx b/apps/hash-frontend/src/components/forms/tags-input.tsx index 32f5e70d044..02a13d848f2 100644 --- a/apps/hash-frontend/src/components/forms/tags-input.tsx +++ b/apps/hash-frontend/src/components/forms/tags-input.tsx @@ -30,11 +30,7 @@ export const TagsInput: FunctionComponent = ({ if ([...delimiters, "Enter"].includes(evt.key)) { evt.preventDefault(); - if ( - text && - (isValid === undefined || isValid(text)) && - !tags.includes(text) - ) { + if (text && (isValid === undefined || isValid(text)) && !tags.includes(text)) { setTags([...tags, text]); inputRef.current.value = ""; } diff --git a/apps/hash-frontend/src/components/forms/text-input.tsx b/apps/hash-frontend/src/components/forms/text-input.tsx index 4f002487fd2..fbe70f5eea0 100644 --- a/apps/hash-frontend/src/components/forms/text-input.tsx +++ b/apps/hash-frontend/src/components/forms/text-input.tsx @@ -32,9 +32,7 @@ export const TextInput = forwardRef( const _onChange = (evt: ChangeEvent) => { if (onChangeText) { onChangeText( - disallowRegExp - ? evt.target.value.replace(disallowRegExp, "") - : evt.target.value, + disallowRegExp ? evt.target.value.replace(disallowRegExp, "") : evt.target.value, ); } else { onChange?.(evt); diff --git a/apps/hash-frontend/src/components/grid/grid.tsx b/apps/hash-frontend/src/components/grid/grid.tsx index 07026c1e53c..0cc324e38c0 100644 --- a/apps/hash-frontend/src/components/grid/grid.tsx +++ b/apps/hash-frontend/src/components/grid/grid.tsx @@ -1,9 +1,5 @@ import "@glideapps/glide-data-grid/dist/index.css"; -import { - CompactSelection, - DataEditor, - GridCellKind, -} from "@glideapps/glide-data-grid"; +import { CompactSelection, DataEditor, GridCellKind } from "@glideapps/glide-data-grid"; import { Box, useTheme } from "@mui/material"; import { uniqueId } from "lodash"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -12,10 +8,7 @@ import { gridRowHeight } from "@local/hash-isomorphic-utils/data-grid"; import { getCellHorizontalPadding } from "./utils"; import { ColumnFilterMenu } from "./utils/column-filter-menu"; -import { - ConversionMenu, - type ConversionTargetsByColumnKey, -} from "./utils/conversion-menu"; +import { ConversionMenu, type ConversionTargetsByColumnKey } from "./utils/conversion-menu"; import { customGridIcons } from "./utils/custom-grid-icons"; import { InteractableManager } from "./utils/interactable-manager"; import { overrideCustomRenderers } from "./utils/override-custom-renderers"; @@ -40,10 +33,7 @@ import type { Theme, } from "@glideapps/glide-data-grid"; import type { PopperProps } from "@mui/material"; -import type { - Instance as PopperInstance, - VirtualElement, -} from "@popperjs/core"; +import type { Instance as PopperInstance, VirtualElement } from "@popperjs/core"; import type { MutableRefObject, Ref } from "react"; export type { ConversionTargetsByColumnKey }; @@ -191,37 +181,28 @@ export const Grid = < return () => InteractableManager.deleteInteractables(tableId); }, []); - const [localSort, setLocalSort] = useState | undefined>( - () => { - const firstSortableColumn = columns.find((column) => - sortableColumns?.includes(column.id as Sortable), - ); + const [localSort, setLocalSort] = useState | undefined>(() => { + const firstSortableColumn = columns.find((column) => + sortableColumns?.includes(column.id as Sortable), + ); - if (firstSortableColumn) { - return { - columnKey: firstSortableColumn.id as Sortable, - direction: "asc", - }; - } - }, - ); + if (firstSortableColumn) { + return { + columnKey: firstSortableColumn.id as Sortable, + direction: "asc", + }; + } + }); const sort = externalSort ?? localSort; const setSort = externalSetSort ?? setLocalSort; if (initialSort && externalSort) { - throw new Error( - "initialSort should not be provided when sort is externally managed", - ); + throw new Error("initialSort should not be provided when sort is externally managed"); } - if ( - (externalSort && !externalSetSort) || - (!externalSort && externalSetSort) - ) { - throw new Error( - "Either both or neither of sort and setSort should be provided", - ); + if ((externalSort && !externalSetSort) || (!externalSort && externalSetSort)) { + throw new Error("Either both or neither of sort and setSort should be provided"); } useEffect(() => { @@ -289,21 +270,18 @@ export const Grid = < tableId: tableIdRef.current, }); - const handleHeaderClicked = useCallback( - (colIndex: number, event: HeaderClickedEventArgs) => { - const columnHeaderPath: ColumnHeaderPath = `${tableIdRef.current}-${colIndex}`; - - /** - * When the header is clicked, we need to notify the interactable manager - * so that the relevant interactables can be notified of the click. - */ - InteractableManager.handleClick(columnHeaderPath, { - posX: event.localEventX, - posY: event.localEventY, - }); - }, - [], - ); + const handleHeaderClicked = useCallback((colIndex: number, event: HeaderClickedEventArgs) => { + const columnHeaderPath: ColumnHeaderPath = `${tableIdRef.current}-${colIndex}`; + + /** + * When the header is clicked, we need to notify the interactable manager + * so that the relevant interactables can be notified of the click. + */ + InteractableManager.handleClick(columnHeaderPath, { + posX: event.localEventX, + posY: event.localEventY, + }); + }, []); const filteredRows = useMemo(() => { if (externallyManagedFiltering) { @@ -386,9 +364,7 @@ export const Grid = < [palette], ); - const getRowThemeOverride = useCallback< - NonNullable - >( + const getRowThemeOverride = useCallback>( (row) => { if (row === hoveredRow) { return { @@ -422,21 +398,16 @@ export const Grid = < [onVisibleRegionChanged], ); - const handleColumnResize = useCallback( - (column: LibraryGridColumn, newSize: number) => { - setColumnSizes((prevColumnSizes) => { - return { - ...prevColumnSizes, - [column.id]: newSize, - }; - }); - }, - [], - ); + const handleColumnResize = useCallback((column: LibraryGridColumn, newSize: number) => { + setColumnSizes((prevColumnSizes) => { + return { + ...prevColumnSizes, + [column.id]: newSize, + }; + }); + }, []); - const resizedColumns = useMemo< - (SizedGridColumn & { width: number })[] - >(() => { + const resizedColumns = useMemo<(SizedGridColumn & { width: number })[]>(() => { return columns.map((col) => { return { ...col, width: columnSizes[col.id] ?? col.width }; }); @@ -465,8 +436,7 @@ export const Grid = < if (!scrollWrapperRef.current) { const setScrollWrapperState = () => { if (wrapperRef.current) { - const mountedScrollWrapper = - wrapperRef.current.querySelector(".dvn-scroller"); + const mountedScrollWrapper = wrapperRef.current.querySelector(".dvn-scroller"); if (mountedScrollWrapper) { scrollWrapperRef.current = mountedScrollWrapper as HTMLDivElement; @@ -487,9 +457,7 @@ export const Grid = < const openFilterColumn = useMemo( () => openFilterColumnKey - ? columnFilters?.find( - ({ columnKey }) => columnKey === openFilterColumnKey, - ) + ? columnFilters?.find(({ columnKey }) => columnKey === openFilterColumnKey) : undefined, [openFilterColumnKey, columnFilters], ); @@ -501,9 +469,7 @@ export const Grid = < return emptyRect; } - const columnIndex = columns.findIndex( - ({ id }) => id === openFilterColumnKey, - ); + const columnIndex = columns.findIndex(({ id }) => id === openFilterColumnKey); /** * We need to obtain the most recent version of the interactable, @@ -522,11 +488,9 @@ export const Grid = < const { y: wrapperYPosition, x: wrapperXPosition } = wrapperRef.current!.getBoundingClientRect(); - const left = - wrapperXPosition + interactable.posRelativeToVisibleGridArea.left; + const left = wrapperXPosition + interactable.posRelativeToVisibleGridArea.left; - const top = - interactable.posRelativeToVisibleGridArea.top + wrapperYPosition; + const top = interactable.posRelativeToVisibleGridArea.top + wrapperYPosition; return { width: 0, @@ -550,9 +514,7 @@ export const Grid = < return emptyRect; } - const columnIndex = columns.findIndex( - ({ id }) => id === openConvertColumnKey, - ); + const columnIndex = columns.findIndex(({ id }) => id === openConvertColumnKey); /** * We need to obtain the most recent version of the interactable, @@ -571,11 +533,9 @@ export const Grid = < const { y: wrapperYPosition, x: wrapperXPosition } = wrapperRef.current!.getBoundingClientRect(); - const left = - wrapperXPosition + interactable.posRelativeToVisibleGridArea.left; + const left = wrapperXPosition + interactable.posRelativeToVisibleGridArea.left; - const top = - interactable.posRelativeToVisibleGridArea.top + wrapperYPosition; + const top = interactable.posRelativeToVisibleGridArea.top + wrapperYPosition; return { width: 0, @@ -627,9 +587,7 @@ export const Grid = < /> {conversionTargetsByColumnKey && onConversionTargetSelected && ( { @@ -681,8 +637,8 @@ export const Grid = < if (onSelectedRowsChange && sortedAndFilteredRows) { newSelection.rows.toArray(); - const updatedSelectedRows = sortedAndFilteredRows.filter( - (_, rowIndex) => newSelection.rows.hasIndex(rowIndex), + const updatedSelectedRows = sortedAndFilteredRows.filter((_, rowIndex) => + newSelection.rows.hasIndex(rowIndex), ); onSelectedRowsChange(updatedSelectedRows); @@ -702,17 +658,14 @@ export const Grid = < theme={gridTheme} verticalBorder={ typeof rest.verticalBorder === "undefined" - ? (columnNumber) => - enableCheckboxSelection ? columnNumber !== 0 : true + ? (columnNumber) => (enableCheckboxSelection ? columnNumber !== 0 : true) : (columnNumber) => { const defaultValue = typeof rest.verticalBorder === "function" ? rest.verticalBorder(columnNumber) : rest.verticalBorder!; - return enableCheckboxSelection - ? columnNumber !== 0 || defaultValue - : defaultValue; + return enableCheckboxSelection ? columnNumber !== 0 || defaultValue : defaultValue; } } {...(enableCheckboxSelection diff --git a/apps/hash-frontend/src/components/grid/utils.ts b/apps/hash-frontend/src/components/grid/utils.ts index c7ee639b82f..08799a9f28f 100644 --- a/apps/hash-frontend/src/components/grid/utils.ts +++ b/apps/hash-frontend/src/components/grid/utils.ts @@ -5,9 +5,7 @@ import type { CustomCell, DrawArgs, Theme } from "@glideapps/glide-data-grid"; /** * @returns vertical center of a grid cell, relative to the visible grid area */ -export const getYCenter = ( - args: Pick, "rect" | "ctx"> & { theme: Theme }, -) => { +export const getYCenter = (args: Pick, "rect" | "ctx"> & { theme: Theme }) => { const { rect, ctx, theme } = args; const { y, height } = rect; @@ -18,8 +16,7 @@ export const getYCenter = ( * @param atFirstColumn first columns has extra padding for the chevron icon on the left side * @returns cell horizontal padding */ -export const getCellHorizontalPadding = (atFirstColumn?: boolean) => - atFirstColumn ? 42 : 22; +export const getCellHorizontalPadding = (atFirstColumn?: boolean) => (atFirstColumn ? 42 : 22); export type BlankCell = CustomCell<{ kind: "blank-cell" }>; diff --git a/apps/hash-frontend/src/components/grid/utils/column-filter-menu.tsx b/apps/hash-frontend/src/components/grid/utils/column-filter-menu.tsx index e724877f5c6..b3fb76daf01 100644 --- a/apps/hash-frontend/src/components/grid/utils/column-filter-menu.tsx +++ b/apps/hash-frontend/src/components/grid/utils/column-filter-menu.tsx @@ -56,27 +56,12 @@ type FilterItemDataProp = { closeMenu: () => void; items: FilterItemData[]; selectedFilterItemIds: Set | undefined; - setSelectedFilterItemIds: - | ((selectedFilterItemIds: Set) => void) - | undefined; + setSelectedFilterItemIds: ((selectedFilterItemIds: Set) => void) | undefined; }; const FilterItem = memo( - ({ - data, - index, - style, - }: { - data: FilterItemDataProp; - index: number; - style: CSSProperties; - }) => { - const { - closeMenu, - items, - selectedFilterItemIds, - setSelectedFilterItemIds, - } = data; + ({ data, index, style }: { data: FilterItemDataProp; index: number; style: CSSProperties }) => { + const { closeMenu, items, selectedFilterItemIds, setSelectedFilterItemIds } = data; const item = items[index]!; const { id, count, doesNotApplyValue, label, labelSuffix, checked } = item; @@ -89,9 +74,7 @@ const FilterItem = memo( setSelectedFilterItemIds?.( checked ? new Set( - [...(selectedFilterItemIds ?? [])].filter( - (selectedId) => selectedId !== id, - ), + [...(selectedFilterItemIds ?? [])].filter((selectedId) => selectedId !== id), ) : new Set([...(selectedFilterItemIds ?? []), id]), ) @@ -108,11 +91,7 @@ const FilterItem = memo( maxWidth: "100%", }} > - + - `${palette.gray[60]} !important`, + color: ({ palette }) => `${palette.gray[60]} !important`, }, } : {} @@ -195,13 +173,11 @@ export const ColumnFilterMenu = ({ columnFilter?: ColumnFilter; onClose: () => void; } & PopperProps) => { - const [previousColumnFilter, setPreviousColumnFilter] = - useState>(); + const [previousColumnFilter, setPreviousColumnFilter] = useState>(); if ( columnFilter && - (!previousColumnFilter || - previousColumnFilter.columnKey !== columnFilter.columnKey) + (!previousColumnFilter || previousColumnFilter.columnKey !== columnFilter.columnKey) ) { setPreviousColumnFilter(columnFilter); } @@ -220,19 +196,14 @@ export const ColumnFilterMenu = ({ closeMenu: () => void; items: FilterItemData[]; selectedFilterItemIds: Set | undefined; - setSelectedFilterItemIds: - | ((selectedFilterItemIds: Set) => void) - | undefined; + setSelectedFilterItemIds: ((selectedFilterItemIds: Set) => void) | undefined; }>(() => { const filteredItems: FilterItemData[] = []; const lowerCasedSearchText = searchText.toLowerCase().trim(); for (const item of filterItems ?? []) { - if ( - searchText && - !item.label.toLowerCase().includes(lowerCasedSearchText) - ) { + if (searchText && !item.label.toLowerCase().includes(lowerCasedSearchText)) { continue; } @@ -282,13 +253,7 @@ export const ColumnFilterMenu = ({ selectedFilterItemIds, setSelectedFilterItemIds, }; - }, [ - filterItems, - onClose, - searchText, - selectedFilterItemIds, - setSelectedFilterItemIds, - ]); + }, [filterItems, onClose, searchText, selectedFilterItemIds, setSelectedFilterItemIds]); return ( diff --git a/apps/hash-frontend/src/components/grid/utils/conversion-menu.tsx b/apps/hash-frontend/src/components/grid/utils/conversion-menu.tsx index fc1a79eec51..918f6161421 100644 --- a/apps/hash-frontend/src/components/grid/utils/conversion-menu.tsx +++ b/apps/hash-frontend/src/components/grid/utils/conversion-menu.tsx @@ -41,9 +41,7 @@ export const ConversionMenu = ({ onSelectConversionTarget: (dataTypeId: VersionedUrl | null) => void; } & PopperProps) => { if (!conversionTargetsByColumnKey) { - throw new Error( - "Conversion menu requires column key and conversion targets", - ); + throw new Error("Conversion menu requires column key and conversion targets"); } if (columnKey && !conversionTargetsByColumnKey[columnKey]) { @@ -122,9 +120,7 @@ export const ConversionMenu = ({ onClose(); }} onChange={(event) => { - const value = event.target.value - ? (event.target.value as VersionedUrl) - : null; + const value = event.target.value ? (event.target.value as VersionedUrl) : null; onSelectConversionTarget(value); onClose(); @@ -145,10 +141,7 @@ export const ConversionMenu = ({ value={activeConversion?.dataTypeId ?? ""} > {activeConversion && ( - palette.red[70] }} - > + palette.red[70] }}> Show original values )} @@ -164,10 +157,7 @@ export const ConversionMenu = ({ {columnKey && conversionTargetsByColumnKey[columnKey]?.map( (target: { dataTypeId: VersionedUrl; title: string }) => ( - + {target.title} ), diff --git a/apps/hash-frontend/src/components/grid/utils/draw-chip-with-icon.ts b/apps/hash-frontend/src/components/grid/utils/draw-chip-with-icon.ts index da3f988641b..38f157e4a40 100644 --- a/apps/hash-frontend/src/components/grid/utils/draw-chip-with-icon.ts +++ b/apps/hash-frontend/src/components/grid/utils/draw-chip-with-icon.ts @@ -4,10 +4,7 @@ import { getChipColors } from "../../../pages/shared/chip-cell"; import { getYCenter } from "../utils"; import { drawChip } from "./draw-chip"; -import type { - ChipCellColor, - ChipCellVariant, -} from "../../../pages/shared/chip-cell"; +import type { ChipCellColor, ChipCellVariant } from "../../../pages/shared/chip-cell"; import type { CustomIcon } from "./custom-grid-icons"; import type { CustomCell, DrawArgs } from "@glideapps/glide-data-grid"; @@ -55,12 +52,7 @@ const getFilledCanvas = ({ offScreenContext.globalCompositeOperation = "source-in"; offScreenContext.fillStyle = fill; - offScreenContext.fillRect( - 0, - 0, - offScreenCanvas.width, - offScreenCanvas.height, - ); + offScreenContext.fillRect(0, 0, offScreenCanvas.width, offScreenCanvas.height); filledIconCanvasCache[iconUrl] ??= {}; filledIconCanvasCache[iconUrl][fill] = offScreenCanvas; @@ -96,11 +88,7 @@ const drawClippedImage = ({ ctx.beginPath(); ctx.moveTo(...topLeftCorner); ctx.lineTo(topRightCorner[0] - borderRadius, topRightCorner[1]); - ctx.quadraticCurveTo( - ...topRightCorner, - topRightCorner[0], - topRightCorner[1] + borderRadius, - ); + ctx.quadraticCurveTo(...topRightCorner, topRightCorner[0], topRightCorner[1] + borderRadius); ctx.lineTo(bottomRightCorner[0], bottomRightCorner[1] - borderRadius); ctx.quadraticCurveTo( ...bottomRightCorner, @@ -114,11 +102,7 @@ const drawClippedImage = ({ bottomLeftCorner[1] - borderRadius, ); ctx.lineTo(topLeftCorner[0], topLeftCorner[1] + borderRadius); - ctx.quadraticCurveTo( - ...topLeftCorner, - topLeftCorner[0] + borderRadius, - topLeftCorner[1], - ); + ctx.quadraticCurveTo(...topLeftCorner, topLeftCorner[0] + borderRadius, topLeftCorner[1]); ctx.closePath(); ctx.clip(); @@ -191,8 +175,7 @@ export const drawChipWithIcon = ({ const iconColor = iconFill ?? defaultColor; - let chipWidth = - iconHeight + gap + textWidth + suffixWidth + suffixPaddingX + 2 * paddingX; + let chipWidth = iconHeight + gap + textWidth + suffixWidth + suffixPaddingX + 2 * paddingX; let chipHeight; let chipTop; @@ -209,8 +192,7 @@ export const drawChipWithIcon = ({ const imageHeight = (image.height / image.width) * width; const imageTop = iconTop + (iconHeight - imageHeight) / 2; - chipWidth = - width + gap + textWidth + suffixWidth + suffixPaddingX + 2 * paddingX; + chipWidth = width + gap + textWidth + suffixWidth + suffixPaddingX + 2 * paddingX; ({ height: chipHeight, top: chipTop } = drawChip( args, @@ -237,13 +219,7 @@ export const drawChipWithIcon = ({ chipHeight = iconHeight; } } else { - ({ height: chipHeight, top: chipTop } = drawChip( - args, - left, - chipWidth, - bgColor, - borderColor, - )); + ({ height: chipHeight, top: chipTop } = drawChip(args, left, chipWidth, bgColor, borderColor)); if (icon && "inbuiltIcon" in icon) { args.spriteManager.drawSprite( @@ -285,10 +261,8 @@ export const drawChipWithIcon = ({ const aspectRatio = image.width / image.height; - const width = - aspectRatio > 1 ? iconHeight : iconHeight * aspectRatio; - const height = - aspectRatio > 1 ? iconHeight / aspectRatio : iconHeight; + const width = aspectRatio > 1 ? iconHeight : iconHeight * aspectRatio; + const height = aspectRatio > 1 ? iconHeight / aspectRatio : iconHeight; ctx.drawImage( canvasWithFill, @@ -303,8 +277,7 @@ export const drawChipWithIcon = ({ } } - const textLeft = - left + chipWidth - paddingX - textWidth - suffixWidth - suffixPaddingX; + const textLeft = left + chipWidth - paddingX - textWidth - suffixWidth - suffixPaddingX; ctx.fillStyle = textColor; ctx.fillText(text, textLeft, yCenter); diff --git a/apps/hash-frontend/src/components/grid/utils/draw-chip-with-text.ts b/apps/hash-frontend/src/components/grid/utils/draw-chip-with-text.ts index 97eb155b4f2..265842fdf27 100644 --- a/apps/hash-frontend/src/components/grid/utils/draw-chip-with-text.ts +++ b/apps/hash-frontend/src/components/grid/utils/draw-chip-with-text.ts @@ -38,13 +38,7 @@ export const drawChipWithText = ({ const textColorInner = textColor ?? theme.textBubble; - drawChip( - args, - left, - chipWidth, - bgColor ?? theme.bgBubble, - borderColor ?? "white", - ); + drawChip(args, left, chipWidth, bgColor ?? theme.bgBubble, borderColor ?? "white"); ctx.fillStyle = textColorInner; ctx.fillText(text, textLeft, yCenter); diff --git a/apps/hash-frontend/src/components/grid/utils/draw-text-with-icon.ts b/apps/hash-frontend/src/components/grid/utils/draw-text-with-icon.ts index 64c0f53e334..dd93d6f85ae 100644 --- a/apps/hash-frontend/src/components/grid/utils/draw-text-with-icon.ts +++ b/apps/hash-frontend/src/components/grid/utils/draw-text-with-icon.ts @@ -31,15 +31,10 @@ export const drawTextWithIcon = ({ const textLeft = iconSize + gap + iconLeft; const fgIconHeader = iconColor ?? theme.textHeader; - args.spriteManager.drawSprite( - icon, - "normal", - ctx, - iconLeft, - yCenter - iconSize / 2, - iconSize, - { ...theme, fgIconHeader }, - ); + args.spriteManager.drawSprite(icon, "normal", ctx, iconLeft, yCenter - iconSize / 2, iconSize, { + ...theme, + fgIconHeader, + }); ctx.fillStyle = textColor ?? theme.textHeader; ctx.fillText(text, textLeft, yCenter); diff --git a/apps/hash-frontend/src/components/grid/utils/interactable-manager.ts b/apps/hash-frontend/src/components/grid/utils/interactable-manager.ts index fe5719aa68a..0671357482a 100644 --- a/apps/hash-frontend/src/components/grid/utils/interactable-manager.ts +++ b/apps/hash-frontend/src/components/grid/utils/interactable-manager.ts @@ -28,10 +28,7 @@ class InteractableManagerClass { * }; * ``` */ - private interactableStore: Record< - CellPath | ColumnHeaderPath, - Record - > = {}; + private interactableStore: Record> = {}; getInteractable(path: CellPath | ColumnHeaderPath, id: string) { return Object.values(this.interactableStore[path] ?? {}).find( @@ -89,10 +86,7 @@ class InteractableManagerClass { * @param args Draw args of cell * @param interactables List of the interactables for a specific cell. */ - setInteractablesForCell( - args: DrawArgs, - interactables: Interactable[], - ) { + setInteractablesForCell(args: DrawArgs, interactables: Interactable[]) { const path = drawArgsToCellPath(args); /** @@ -103,9 +97,7 @@ class InteractableManagerClass { const existing = this.interactableStore[path]?.[interactable.id]; if (existing && existing.hovered !== interactable.hovered) { - const event = interactable.hovered - ? interactable.onMouseEnter - : interactable.onMouseLeave; + const event = interactable.hovered ? interactable.onMouseEnter : interactable.onMouseLeave; event?.(interactable); } @@ -123,10 +115,7 @@ class InteractableManagerClass { * @param args Draw args of column header * @param interactables List of the interactables for a specific column header. */ - setInteractablesForColumnHeader( - args: ColumnHeaderDrawArgs, - interactables: Interactable[], - ) { + setInteractablesForColumnHeader(args: ColumnHeaderDrawArgs, interactables: Interactable[]) { const path = drawArgsToColumnHeaderPath(args); /** @todo: trigger on mouse enter/leave events? */ @@ -185,10 +174,7 @@ class InteractableManagerClass { const { rowIndex } = splitPath(path); - if ( - rowIndex < boundaries.deleteBeforeRow || - rowIndex > boundaries.deleteAfterRow - ) { + if (rowIndex < boundaries.deleteBeforeRow || rowIndex > boundaries.deleteAfterRow) { return true; } } diff --git a/apps/hash-frontend/src/components/grid/utils/interactable-manager/utils.ts b/apps/hash-frontend/src/components/grid/utils/interactable-manager/utils.ts index 23bdb95c7f5..e20d39cc6f6 100644 --- a/apps/hash-frontend/src/components/grid/utils/interactable-manager/utils.ts +++ b/apps/hash-frontend/src/components/grid/utils/interactable-manager/utils.ts @@ -5,24 +5,17 @@ import type { CursorPos, InteractablePosition, } from "./types"; -import type { - CustomCell, - DrawArgs, - Rectangle, -} from "@glideapps/glide-data-grid"; +import type { CustomCell, DrawArgs, Rectangle } from "@glideapps/glide-data-grid"; -export const isPathCellPath = ( - path: CellPath | ColumnHeaderPath, -): path is CellPath => path.split("-").length === 3; +export const isPathCellPath = (path: CellPath | ColumnHeaderPath): path is CellPath => + path.split("-").length === 3; export const drawArgsToCellPath = (args: DrawArgs): CellPath => { const { tableId, col, row } = args; return `${tableId}-${col}-${row}`; }; -export const drawArgsToColumnHeaderPath = ( - args: ColumnHeaderDrawArgs, -): ColumnHeaderPath => { +export const drawArgsToColumnHeaderPath = (args: ColumnHeaderDrawArgs): ColumnHeaderPath => { const { tableId, columnIndex } = args; return `${tableId}-${columnIndex}`; }; @@ -31,9 +24,7 @@ export const splitPath = (path: CellPath) => { const [tableId, colIndex, rowIndex] = path.split("-"); if (!tableId || !colIndex || !rowIndex) { - throw new Error( - `CellPath should have '{tableId}-{colIndex}-{rowIndex}' format`, - ); + throw new Error(`CellPath should have '{tableId}-{colIndex}-{rowIndex}' format`); } return { @@ -56,8 +47,7 @@ export const isCursorOnInteractable = ( const cursorX = cursorPos.posX; const cursorY = cursorPos.posY; - const hovered = - cursorX > left && cursorX < right && cursorY < bottom && cursorY > top; + const hovered = cursorX > left && cursorX < right && cursorY < bottom && cursorY > top; return hovered; }; diff --git a/apps/hash-frontend/src/components/grid/utils/override-custom-renderers.tsx b/apps/hash-frontend/src/components/grid/utils/override-custom-renderers.tsx index 2589c9265ee..23c97c3b07b 100644 --- a/apps/hash-frontend/src/components/grid/utils/override-custom-renderers.tsx +++ b/apps/hash-frontend/src/components/grid/utils/override-custom-renderers.tsx @@ -21,11 +21,7 @@ import type { DataEditorProps } from "@glideapps/glide-data-grid"; * * @todo make the slide stacks consistent when this becomes an issue, and lock the slide scroll. */ -const ScrollLockWrapper = ({ - children, -}: { - children: ReactNode | Promise; -}) => { +const ScrollLockWrapper = ({ children }: { children: ReactNode | Promise }) => { const { currentSlideRef } = useSlideStack(); useScrollLock(true, currentSlideRef?.current ?? document.body); @@ -46,47 +42,40 @@ export const overrideCustomRenderers = ( customRenderers: DataEditorProps["customRenderers"], tableIdRef: RefObject, ): DataEditorProps["customRenderers"] => { - return customRenderers?.map( - ({ draw, provideEditor, onClick, ...restFields }) => { - return { - ...restFields, - draw: (args, cell) => - draw({ ...args, tableId: tableIdRef.current }, cell), - onClick: (args) => { - const [colIndex, rowIndex] = args.location; + return customRenderers?.map(({ draw, provideEditor, onClick, ...restFields }) => { + return { + ...restFields, + draw: (args, cell) => draw({ ...args, tableId: tableIdRef.current }, cell), + onClick: (args) => { + const [colIndex, rowIndex] = args.location; - const wasClickHandledByManager = InteractableManager.handleClick( - `${tableIdRef.current}-${colIndex}-${rowIndex}`, - args, - ); + const wasClickHandledByManager = InteractableManager.handleClick( + `${tableIdRef.current}-${colIndex}-${rowIndex}`, + args, + ); - if (wasClickHandledByManager) { - args.preventDefault(); - } else { - onClick?.(args); - } + if (wasClickHandledByManager) { + args.preventDefault(); + } else { + onClick?.(args); + } - return undefined; - }, - provideEditor: (cell) => { - const editorProps = provideEditor?.(cell); + return undefined; + }, + provideEditor: (cell) => { + const editorProps = provideEditor?.(cell); - return { - ...editorProps, - editor: (props) => { - if (isObjectEditorCallbackResult(editorProps)) { - return ( - - {editorProps.editor(props)} - - ); - } + return { + ...editorProps, + editor: (props) => { + if (isObjectEditorCallbackResult(editorProps)) { + return {editorProps.editor(props)}; + } - return null; - }, - }; - }, - }; - }, - ); + return null; + }, + }; + }, + }; + }); }; diff --git a/apps/hash-frontend/src/components/grid/utils/sorting.ts b/apps/hash-frontend/src/components/grid/utils/sorting.ts index 56b9e95e375..1dfe738c2eb 100644 --- a/apps/hash-frontend/src/components/grid/utils/sorting.ts +++ b/apps/hash-frontend/src/components/grid/utils/sorting.ts @@ -21,8 +21,7 @@ export const defaultSortRows = < const value2 = row2[sort.columnKey as keyof Row]; if (typeof value1 === "number" && typeof value2 === "number") { - const difference = - (value1 - value2) * (sort.direction === "asc" ? 1 : -1); + const difference = (value1 - value2) * (sort.direction === "asc" ? 1 : -1); return difference; } diff --git a/apps/hash-frontend/src/components/grid/utils/use-draw-header.ts b/apps/hash-frontend/src/components/grid/utils/use-draw-header.ts index 0b88c67a37e..0160e745f42 100644 --- a/apps/hash-frontend/src/components/grid/utils/use-draw-header.ts +++ b/apps/hash-frontend/src/components/grid/utils/use-draw-header.ts @@ -6,26 +6,15 @@ import { InteractableManager } from "./interactable-manager"; import type { ColumnKey, ConversionTargetsByColumnKey } from "../grid"; import type { ColumnFilter } from "./filtering"; -import type { - Interactable, - InteractablePosition, -} from "./interactable-manager/types"; +import type { Interactable, InteractablePosition } from "./interactable-manager/types"; import type { ColumnSort } from "./sorting"; import type { BaseUrl, VersionedUrl } from "@blockprotocol/type-system"; -import type { - DrawHeaderCallback, - SizedGridColumn, -} from "@glideapps/glide-data-grid"; - -export const generateInteractableId = ( - type: "filter" | "sort" | "convert", - columnKey: string, -) => `column-${type}-${columnKey}`; - -export const useDrawHeader = < - C extends SizedGridColumn, - S extends C["id"], ->(props: { +import type { DrawHeaderCallback, SizedGridColumn } from "@glideapps/glide-data-grid"; + +export const generateInteractableId = (type: "filter" | "sort" | "convert", columnKey: string) => + `column-${type}-${columnKey}`; + +export const useDrawHeader = (props: { activeConversions?: { [columnBaseUrl: BaseUrl]: { dataTypeId: VersionedUrl; title: string }; } | null; @@ -34,14 +23,8 @@ export const useDrawHeader = < // eslint-disable-next-line @typescript-eslint/no-explicit-any filters?: ColumnFilter, any>[]; firstColumnLeftPadding?: number; - onConvertClicked?: ( - columnKey: ColumnKey, - interactablePosition: InteractablePosition, - ) => void; - onFilterClick?: ( - columnKey: ColumnKey, - interactablePosition: InteractablePosition, - ) => void; + onConvertClicked?: (columnKey: ColumnKey, interactablePosition: InteractablePosition) => void; + onFilterClick?: (columnKey: ColumnKey, interactablePosition: InteractablePosition) => void; onSortClick?: (columnKey: S) => void; sort?: ColumnSort; sortableColumns: S[]; @@ -99,8 +82,7 @@ export const useDrawHeader = < if (isSortable) { const sortIconStartX = - columnHeaderStartX + - (columnHeaderWidth - sortIconSize - paddingRight); + columnHeaderStartX + (columnHeaderWidth - sortIconSize - paddingRight); const isSortActive = sort.columnKey === columnKey; @@ -116,9 +98,7 @@ export const useDrawHeader = < sortIconSize, { ...theme, - fgIconHeader: isSortActive - ? muiTheme.palette.blue[70] - : muiTheme.palette.gray[50], + fgIconHeader: isSortActive ? muiTheme.palette.blue[70] : muiTheme.palette.gray[50], }, 1, ); @@ -140,9 +120,7 @@ export const useDrawHeader = < ); } - const columnFilter = filters?.find( - (filter) => filter.columnKey === columnKey, - ); + const columnFilter = filters?.find((filter) => filter.columnKey === columnKey); const filterIconSize = 15; @@ -155,8 +133,7 @@ export const useDrawHeader = < filterIconSize); const isFilterModified = - columnFilter.selectedFilterItemIds.size !== - columnFilter.filterItems.length; + columnFilter.selectedFilterItemIds.size !== columnFilter.filterItems.length; args.spriteManager.drawSprite( "filterLight", @@ -167,9 +144,7 @@ export const useDrawHeader = < filterIconSize, { ...theme, - fgIconHeader: isFilterModified - ? muiTheme.palette.blue[70] - : muiTheme.palette.gray[50], + fgIconHeader: isFilterModified ? muiTheme.palette.blue[70] : muiTheme.palette.gray[50], }, 1, ); @@ -186,10 +161,7 @@ export const useDrawHeader = < bottom: centerY + filterIconSize / 2, }, onClick: (interactable) => - onFilterClick?.( - columnKey, - interactable.posRelativeToVisibleGridArea, - ), + onFilterClick?.(columnKey, interactable.posRelativeToVisibleGridArea), }, ), ); @@ -239,20 +211,14 @@ export const useDrawHeader = < bottom: centerY + calculatorIconSize / 2, }, onClick: (interactable) => - onConvertClicked?.( - columnKey, - interactable.posRelativeToVisibleGridArea, - ), + onConvertClicked?.(columnKey, interactable.posRelativeToVisibleGridArea), }, ), ); } if (interactables.length > 0) { - InteractableManager.setInteractablesForColumnHeader( - { ...args, tableId }, - interactables, - ); + InteractableManager.setInteractablesForColumnHeader({ ...args, tableId }, interactables); } return true; diff --git a/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip.tsx b/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip.tsx index 9439a364d63..86c40334f47 100644 --- a/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip.tsx +++ b/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip.tsx @@ -67,9 +67,7 @@ export const useGridTooltip = ( const interactableStartX = bounds.x + ("right" in interactablePosRelativeToCell - ? bounds.width - - interactableSize.width - - interactablePosRelativeToCell.right + ? bounds.width - interactableSize.width - interactablePosRelativeToCell.right : interactablePosRelativeToCell.left); const interactableStartY = bounds.y + interactablePosRelativeToCell.top; @@ -93,8 +91,7 @@ export const useGridTooltip = ( const showTooltip = useCallback( (newTooltip) => { - const isEditorOpen = - !!document.querySelector(`div[id="portal"]`)?.children.length; + const isEditorOpen = !!document.querySelector(`div[id="portal"]`)?.children.length; if (isEditorOpen) { return; @@ -135,10 +132,7 @@ export const useGridTooltip = ( const hideTooltip = useCallback( (colIndex, rowIndex) => { - if ( - gridTooltip?.colIndex === colIndex && - gridTooltip.rowIndex === rowIndex - ) { + if (gridTooltip?.colIndex === colIndex && gridTooltip.rowIndex === rowIndex) { popupState.close(); setGridTooltip(null); } diff --git a/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip/draw-interactable-tooltip-icons.ts b/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip/draw-interactable-tooltip-icons.ts index e2c395f5422..fe5bf8dd6be 100644 --- a/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip/draw-interactable-tooltip-icons.ts +++ b/apps/hash-frontend/src/components/grid/utils/use-grid-tooltip/draw-interactable-tooltip-icons.ts @@ -10,9 +10,7 @@ const iconSize = 16; const iconGap = 10; const cellMargin = getCellHorizontalPadding(); -export const drawInteractableTooltipIcons = ( - args: DrawArgs, -): Interactable[] => { +export const drawInteractableTooltipIcons = (args: DrawArgs): Interactable[] => { const { ctx, cell, rect, col, row, theme } = args; const { hideTooltip, showTooltip, tooltips } = cell.data; diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/knowledge-shim.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/knowledge-shim.ts index 401b74ac450..9a256b46ca4 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/knowledge-shim.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/knowledge-shim.ts @@ -19,12 +19,7 @@ import type { Subgraph, UploadFileData as BpUploadFileData, } from "@blockprotocol/graph"; -import type { - EntityId, - LinkData, - PropertyObject, - VersionedUrl, -} from "@blockprotocol/type-system"; +import type { EntityId, LinkData, PropertyObject, VersionedUrl } from "@blockprotocol/type-system"; import type { HashEntity } from "@local/hash-graph-sdk/entity"; import type { File as FileEntity } from "@local/hash-isomorphic-utils/system-types/shared"; import type { diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-archive-entity.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-archive-entity.ts index 0939a28acd3..677464fbda0 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-archive-entity.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-archive-entity.ts @@ -14,10 +14,9 @@ export const useBlockProtocolArchiveEntity = ( ): { archiveEntity: ArchiveEntityMessageCallback; } => { - const [archiveEntityFn] = useMutation< - ArchiveEntityMutation, - ArchiveEntityMutationVariables - >(archiveEntityMutation); + const [archiveEntityFn] = useMutation( + archiveEntityMutation, + ); const archiveEntity: ArchiveEntityMessageCallback = useCallback( async ({ data }) => { diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-create-entity.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-create-entity.ts index cdf1bd0a2fe..e23bbbd4c4b 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-create-entity.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-create-entity.ts @@ -1,10 +1,7 @@ import { useMutation } from "@apollo/client"; import { useCallback } from "react"; -import { - HashEntity, - mergePropertyObjectAndMetadata, -} from "@local/hash-graph-sdk/entity"; +import { HashEntity, mergePropertyObjectAndMetadata } from "@local/hash-graph-sdk/entity"; import { createEntityMutation, @@ -28,26 +25,26 @@ export const useBlockProtocolCreateEntity = ( } => { const { activeWorkspaceWebId } = useActiveWorkspace(); - const [createFn] = useMutation< - CreateEntityMutation, - CreateEntityMutationVariables - >(createEntityMutation, { - refetchQueries: activeWorkspaceWebId - ? [ - /** - * This refetch query accounts for the "Entities" section - * in the sidebar being updated when the first instance of - * a type is created by a user that is from a different web. - */ - { - query: queryEntitySubgraphQuery, - variables: generateSidebarEntityTypeEntitiesQueryVariables({ - webId: activeWorkspaceWebId, - }), - }, - ] - : [], - }); + const [createFn] = useMutation( + createEntityMutation, + { + refetchQueries: activeWorkspaceWebId + ? [ + /** + * This refetch query accounts for the "Entities" section + * in the sidebar being updated when the first instance of + * a type is created by a user that is from a different web. + */ + { + query: queryEntitySubgraphQuery, + variables: generateSidebarEntityTypeEntitiesQueryVariables({ + webId: activeWorkspaceWebId, + }), + }, + ] + : [], + }, + ); const createEntity: CreateEntityMessageCallback = useCallback( async ({ data }) => { diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-file-upload.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-file-upload.ts index 4b5d654707e..83f05bae492 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-file-upload.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-file-upload.ts @@ -70,8 +70,7 @@ export const useBlockProtocolFileUpload = ( return { errors: [ { - message: - "An error occurred while creating a file from an external link", + message: "An error occurred while creating a file from an external link", code: "INTERNAL_ERROR", }, ], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-get-entity.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-get-entity.ts index d1bd7cf6fd1..97637efbdfd 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-get-entity.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-get-entity.ts @@ -78,9 +78,7 @@ export const useBlockProtocolGetEntity = (): { } return { - data: deserializeQueryEntitySubgraphResponse( - response.queryEntitySubgraph, - ).subgraph, + data: deserializeQueryEntitySubgraphResponse(response.queryEntitySubgraph).subgraph, }; }, [queryEntitySubgraphFn], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-query-entities.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-query-entities.ts index 690e6357b78..b1c8fac70d6 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-query-entities.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-query-entities.ts @@ -16,12 +16,12 @@ import type { QueryEntitiesMessageCallback } from "./knowledge-shim"; export const useBlockProtocolQueryEntities = (): { queryEntities: QueryEntitiesMessageCallback; } => { - const [queryFn] = useLazyQuery< - QueryEntitySubgraphQuery, - QueryEntitySubgraphQueryVariables - >(queryEntitySubgraphQuery, { - fetchPolicy: "cache-and-network", - }); + const [queryFn] = useLazyQuery( + queryEntitySubgraphQuery, + { + fetchPolicy: "cache-and-network", + }, + ); const queryEntities = useCallback( async ({ data }) => { @@ -39,9 +39,7 @@ export const useBlockProtocolQueryEntities = (): { const { operation, ...additionalParams } = data; if (operation.multiSort !== undefined && operation.multiSort !== null) { - throw new Error( - "Sorting on queryEntities results is not currently supported", - ); + throw new Error("Sorting on queryEntities results is not currently supported"); } /** diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-update-entity.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-update-entity.ts index c7855cb92a6..f1c8f182266 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-update-entity.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/knowledge/use-block-protocol-update-entity.ts @@ -20,10 +20,9 @@ export const useBlockProtocolUpdateEntity = ( ): { updateEntity: UpdateEntityMessageCallback; } => { - const [updateFn] = useMutation< - UpdateEntityMutation, - UpdateEntityMutationVariables - >(updateEntityMutation); + const [updateFn] = useMutation( + updateEntityMutation, + ); const updateEntity = useCallback( async ({ data }) => { diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-entity-type.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-entity-type.ts index a9f647e8ece..d13780c1fa9 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-entity-type.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-entity-type.ts @@ -16,10 +16,9 @@ export const useBlockProtocolCreateEntityType = ( ): { createEntityType: CreateEntityTypeMessageCallback; } => { - const [createFn] = useMutation< - CreateEntityTypeMutation, - CreateEntityTypeMutationVariables - >(createEntityTypeMutation); + const [createFn] = useMutation( + createEntityTypeMutation, + ); const createEntityType: CreateEntityTypeMessageCallback = useCallback( async ({ data }) => { diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-property-type.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-property-type.ts index 801377d82d7..fcb75bd8345 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-property-type.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-create-property-type.ts @@ -16,10 +16,9 @@ export const useBlockProtocolCreatePropertyType = ( ): { createPropertyType: CreatePropertyTypeMessageCallback; } => { - const [createFn] = useMutation< - CreatePropertyTypeMutation, - CreatePropertyTypeMutationVariables - >(createPropertyTypeMutation); + const [createFn] = useMutation( + createPropertyTypeMutation, + ); const createPropertyType: CreatePropertyTypeMessageCallback = useCallback( async ({ data }) => { diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-data-type.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-data-type.ts index 5de62f20c12..7faed03302d 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-data-type.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-data-type.ts @@ -18,13 +18,13 @@ import type { GetDataTypeMessageCallback } from "./ontology-types-shim"; export const useBlockProtocolGetDataType = (): { getDataType: GetDataTypeMessageCallback; } => { - const [getFn] = useLazyQuery< - QueryDataTypeSubgraphQuery, - QueryDataTypeSubgraphQueryVariables - >(queryDataTypeSubgraphQuery, { - // Data types are immutable, any request for an dataTypeId should always return the same value. - fetchPolicy: "cache-first", - }); + const [getFn] = useLazyQuery( + queryDataTypeSubgraphQuery, + { + // Data types are immutable, any request for an dataTypeId should always return the same value. + fetchPolicy: "cache-first", + }, + ); const getDataType = useCallback( async ({ data: dataTypeId }) => { @@ -64,9 +64,8 @@ export const useBlockProtocolGetDataType = (): { } return { - data: deserializeQueryDataTypeSubgraphResponse( - response.data.queryDataTypeSubgraph, - ).subgraph, + data: deserializeQueryDataTypeSubgraphResponse(response.data.queryDataTypeSubgraph) + .subgraph, }; }, [getFn], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-entity-type.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-entity-type.ts index 37d37a0d049..cf33fa28a07 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-entity-type.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-entity-type.ts @@ -18,19 +18,19 @@ import type { GetEntityTypeMessageCallback } from "./ontology-types-shim"; export const useBlockProtocolGetEntityType = (): { getEntityType: GetEntityTypeMessageCallback; } => { - const [getFn] = useLazyQuery< - QueryEntityTypeSubgraphQuery, - QueryEntityTypeSubgraphQueryVariables - >(queryEntityTypeSubgraphQuery, { - /** - * Entity types are immutable, any request for an entityTypeId should always return the same value. - * However, currently requests for non-existent entity types currently return an empty subgraph, so - * we can't rely on this. - * - * @todo revert this back to cache-first once that's fixed - */ - fetchPolicy: "network-only", - }); + const [getFn] = useLazyQuery( + queryEntityTypeSubgraphQuery, + { + /** + * Entity types are immutable, any request for an entityTypeId should always return the same value. + * However, currently requests for non-existent entity types currently return an empty subgraph, so + * we can't rely on this. + * + * @todo revert this back to cache-first once that's fixed + */ + fetchPolicy: "network-only", + }, + ); const getEntityType = useCallback( async ({ data }) => { @@ -76,9 +76,8 @@ export const useBlockProtocolGetEntityType = (): { } return { - data: deserializeQueryEntityTypeSubgraphResponse( - response.data.queryEntityTypeSubgraph, - ).subgraph, + data: deserializeQueryEntityTypeSubgraphResponse(response.data.queryEntityTypeSubgraph) + .subgraph, }; }, [getFn], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-property-type.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-property-type.ts index 6d699ec278f..77a005c4d2a 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-property-type.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-get-property-type.ts @@ -51,10 +51,7 @@ export const useBlockProtocolGetPropertyType = (): { variables: { request: { filter: { - equal: [ - { path: ["versionedUrl"] }, - { parameter: propertyTypeId }, - ], + equal: [{ path: ["versionedUrl"] }, { parameter: propertyTypeId }], }, temporalAxes: currentTimeInstantTemporalAxes, graphResolveDepths: { @@ -78,9 +75,8 @@ export const useBlockProtocolGetPropertyType = (): { } return { - data: deserializeQueryPropertyTypeSubgraphResponse( - response.data.queryPropertyTypeSubgraph, - ).subgraph, + data: deserializeQueryPropertyTypeSubgraphResponse(response.data.queryPropertyTypeSubgraph) + .subgraph, }; }, [getFn], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-data-types.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-data-types.ts index 7471ae7a576..733e1c65219 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-data-types.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-data-types.ts @@ -18,12 +18,12 @@ import type { QueryDataTypesMessageCallback } from "./ontology-types-shim"; export const useBlockProtocolQueryDataTypes = (): { queryDataTypes: QueryDataTypesMessageCallback; } => { - const [queryFn] = useLazyQuery< - QueryDataTypeSubgraphQuery, - QueryDataTypeSubgraphQueryVariables - >(queryDataTypeSubgraphQuery, { - fetchPolicy: "cache-and-network", - }); + const [queryFn] = useLazyQuery( + queryDataTypeSubgraphQuery, + { + fetchPolicy: "cache-and-network", + }, + ); const queryDataTypes = useCallback( async ({ data }) => { @@ -69,9 +69,8 @@ export const useBlockProtocolQueryDataTypes = (): { } return { - data: deserializeQueryDataTypeSubgraphResponse( - response.data.queryDataTypeSubgraph, - ).subgraph, + data: deserializeQueryDataTypeSubgraphResponse(response.data.queryDataTypeSubgraph) + .subgraph, }; }, [queryFn], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-entity-types.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-entity-types.ts index 76415034fde..48e36d2fd39 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-entity-types.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-entity-types.ts @@ -77,9 +77,8 @@ export const useBlockProtocolQueryEntityTypes = (): { } return { - data: deserializeQueryEntityTypeSubgraphResponse( - response.data.queryEntityTypeSubgraph, - ).subgraph, + data: deserializeQueryEntityTypeSubgraphResponse(response.data.queryEntityTypeSubgraph) + .subgraph, }; }, [queryFn], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-property-types.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-property-types.ts index b64fb2d3cdd..31198bb93eb 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-property-types.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-query-property-types.ts @@ -76,9 +76,8 @@ export const useBlockProtocolQueryPropertyTypes = (): { } return { - data: deserializeQueryPropertyTypeSubgraphResponse( - response.data.queryPropertyTypeSubgraph, - ).subgraph, + data: deserializeQueryPropertyTypeSubgraphResponse(response.data.queryPropertyTypeSubgraph) + .subgraph, }; }, [queryFn], diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-entity-type.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-entity-type.ts index 2e384a5c4cf..438678ab7bb 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-entity-type.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-entity-type.ts @@ -14,10 +14,9 @@ export const useBlockProtocolUpdateEntityType = ( ): { updateEntityType: UpdateEntityTypeMessageCallback; } => { - const [updateFn] = useMutation< - UpdateEntityTypeMutation, - UpdateEntityTypeMutationVariables - >(updateEntityTypeMutation); + const [updateFn] = useMutation( + updateEntityTypeMutation, + ); const updateEntityType: UpdateEntityTypeMessageCallback = useCallback( async ({ data }) => { diff --git a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-property-type.ts b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-property-type.ts index 0cb2af91177..cb753a0d7bb 100644 --- a/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-property-type.ts +++ b/apps/hash-frontend/src/components/hooks/block-protocol-functions/ontology/use-block-protocol-update-property-type.ts @@ -14,10 +14,9 @@ export const useBlockProtocolUpdatePropertyType = ( ): { updatePropertyType: UpdatePropertyTypeMessageCallback; } => { - const [updateFn] = useMutation< - UpdatePropertyTypeMutation, - UpdatePropertyTypeMutationVariables - >(updatePropertyTypeMutation); + const [updateFn] = useMutation( + updatePropertyTypeMutation, + ); const updatePropertyType: UpdatePropertyTypeMessageCallback = useCallback( async ({ data }) => { diff --git a/apps/hash-frontend/src/components/hooks/use-account-pages.ts b/apps/hash-frontend/src/components/hooks/use-account-pages.ts index e261cc67334..a69b96e06d2 100644 --- a/apps/hash-frontend/src/components/hooks/use-account-pages.ts +++ b/apps/hash-frontend/src/components/hooks/use-account-pages.ts @@ -1,10 +1,7 @@ import { useQuery } from "@apollo/client"; import { useMemo } from "react"; -import { - getOutgoingLinkAndTargetEntities, - getRoots, -} from "@blockprotocol/graph/stdlib"; +import { getOutgoingLinkAndTargetEntities, getRoots } from "@blockprotocol/graph/stdlib"; import { deserializeQueryEntitySubgraphResponse } from "@local/hash-graph-sdk/entity"; import { systemEntityTypes, @@ -38,10 +35,7 @@ export type AccountPagesInfo = { refetch: () => Promise>; }; -export const useAccountPages = ( - webId?: WebId, - includeArchived?: boolean, -): AccountPagesInfo => { +export const useAccountPages = (webId?: WebId, includeArchived?: boolean): AccountPagesInfo => { const { hashInstance } = useHashInstance(); const { data, loading, refetch } = useQuery< @@ -82,9 +76,7 @@ export const useAccountPages = ( ...simplifyProperties(latestPage.properties as PageProperties), metadata: latestPage.metadata, parentPage: parentPage ? { metadata: parentPage.metadata } : null, - type: latestPage.metadata.entityTypeIds.includes( - systemEntityTypes.canvas.entityTypeId, - ) + type: latestPage.metadata.entityTypeIds.includes(systemEntityTypes.canvas.entityTypeId) ? "canvas" : "document", }; diff --git a/apps/hash-frontend/src/components/hooks/use-archive-page.ts b/apps/hash-frontend/src/components/hooks/use-archive-page.ts index 64e263010f4..01c7ace92ab 100644 --- a/apps/hash-frontend/src/components/hooks/use-archive-page.ts +++ b/apps/hash-frontend/src/components/hooks/use-archive-page.ts @@ -11,19 +11,16 @@ import { updatePage } from "../../graphql/queries/page.queries"; import { getBlockCollectionContentsStructuralQueryVariables } from "../../pages/shared/block-collection-contents"; import { getAccountPagesVariables } from "../../shared/account-pages-variables"; -import type { - UpdatePageMutation, - UpdatePageMutationVariables, -} from "../../graphql/api-types.gen"; +import type { UpdatePageMutation, UpdatePageMutationVariables } from "../../graphql/api-types.gen"; import type { EntityId } from "@blockprotocol/type-system"; export const useArchivePage = () => { - const [updatePageFn, { loading }] = useMutation< - UpdatePageMutation, - UpdatePageMutationVariables - >(updatePage, { - awaitRefetchQueries: false, - }); + const [updatePageFn, { loading }] = useMutation( + updatePage, + { + awaitRefetchQueries: false, + }, + ); const getRefetchQueries = useCallback((pageEntityId: EntityId) => { const webId = extractWebIdFromEntityId(pageEntityId); diff --git a/apps/hash-frontend/src/components/hooks/use-create-page.ts b/apps/hash-frontend/src/components/hooks/use-create-page.ts index ac1f214a34b..85db73432db 100644 --- a/apps/hash-frontend/src/components/hooks/use-create-page.ts +++ b/apps/hash-frontend/src/components/hooks/use-create-page.ts @@ -13,19 +13,10 @@ import { createPage } from "../../graphql/queries/page.queries"; import { constructPageRelativeUrl } from "../../lib/routes"; import { getAccountPagesVariables } from "../../shared/account-pages-variables"; -import type { - CreatePageMutation, - CreatePageMutationVariables, -} from "../../graphql/api-types.gen"; +import type { CreatePageMutation, CreatePageMutationVariables } from "../../graphql/api-types.gen"; import type { WebId } from "@blockprotocol/type-system"; -export const useCreatePage = ({ - shortname, - webId, -}: { - shortname?: string; - webId?: WebId; -}) => { +export const useCreatePage = ({ shortname, webId }: { shortname?: string; webId?: WebId }) => { const router = useRouter(); const [createPageFn, { loading: createPageLoading }] = useMutation< @@ -39,9 +30,7 @@ export const useCreatePage = ({ { query: queryEntitySubgraphQuery, variables: getAccountPagesVariables({ - webId: extractWebIdFromEntityId( - data.createPage.metadata.recordId.entityId, - ), + webId: extractWebIdFromEntityId(data.createPage.metadata.recordId.entityId), }), }, ] diff --git a/apps/hash-frontend/src/components/hooks/use-create-sub-page.ts b/apps/hash-frontend/src/components/hooks/use-create-sub-page.ts index a7dd7a4f7ee..4da9d20b6a0 100644 --- a/apps/hash-frontend/src/components/hooks/use-create-sub-page.ts +++ b/apps/hash-frontend/src/components/hooks/use-create-sub-page.ts @@ -18,13 +18,7 @@ import type { } from "../../graphql/api-types.gen"; import type { EntityId, WebId } from "@blockprotocol/type-system"; -export const useCreateSubPage = ({ - shortname, - webId, -}: { - shortname?: string; - webId?: WebId; -}) => { +export const useCreateSubPage = ({ shortname, webId }: { shortname?: string; webId?: WebId }) => { const router = useRouter(); const [createPageFn, { loading: createPageLoading }] = useMutation< @@ -66,8 +60,7 @@ export const useCreateSubPage = ({ }); if (response.data?.createPage) { - const pageEntityId = - response.data.createPage.metadata.recordId.entityId; + const pageEntityId = response.data.createPage.metadata.recordId.entityId; await setParentPageFn({ variables: { @@ -91,8 +84,5 @@ export const useCreateSubPage = ({ [createPageFn, webId, setParentPageFn, router, shortname], ); - return [ - createSubPage, - { loading: createPageLoading || setParentPageLoading }, - ] as const; + return [createSubPage, { loading: createPageLoading || setParentPageLoading }] as const; }; diff --git a/apps/hash-frontend/src/components/hooks/use-default-state.tsx b/apps/hash-frontend/src/components/hooks/use-default-state.tsx index 6f2385bee93..2e2a092afed 100644 --- a/apps/hash-frontend/src/components/hooks/use-default-state.tsx +++ b/apps/hash-frontend/src/components/hooks/use-default-state.tsx @@ -3,12 +3,9 @@ import { useCallback, useState } from "react"; import type { Dispatch, SetStateAction } from "react"; -export const useDefaultState = < - T extends object | number | string | boolean | null | undefined, ->( +export const useDefaultState = ( defaultValue: T, - produceNextValue: (nextValue: T, currentValue: T) => T = (nextValue) => - nextValue, + produceNextValue: (nextValue: T, currentValue: T) => T = (nextValue) => nextValue, ): [T, Dispatch>] => { const [{ prevDefault, currentValue }, setNextValue] = useState({ prevDefault: defaultValue, @@ -24,8 +21,7 @@ export const useDefaultState = < const setState = useCallback((value: SetStateAction) => { setNextValue((prevValue) => { - const nextValue = - typeof value === "function" ? value(prevValue.currentValue) : value; + const nextValue = typeof value === "function" ? value(prevValue.currentValue) : value; return { ...prevValue, @@ -44,8 +40,7 @@ export const useCachedDefaultState = < >( defaultValue: T, key: string, - produceNextValue: (nextValue: T, currentValue: T) => T = (nextValue) => - nextValue, + produceNextValue: (nextValue: T, currentValue: T) => T = (nextValue) => nextValue, ): [T, Dispatch>] => { const [{ prevDefault, currentValue }, setNextValue] = useLocalStorage({ key, @@ -66,8 +61,7 @@ export const useCachedDefaultState = < const setState = useCallback( (value: SetStateAction) => { setNextValue((prevValue) => { - const nextValue = - typeof value === "function" ? value(prevValue.currentValue) : value; + const nextValue = typeof value === "function" ? value(prevValue.currentValue) : value; return { ...prevValue, diff --git a/apps/hash-frontend/src/components/hooks/use-entity-by-id.ts b/apps/hash-frontend/src/components/hooks/use-entity-by-id.ts index d1205293023..38625e89aa1 100644 --- a/apps/hash-frontend/src/components/hooks/use-entity-by-id.ts +++ b/apps/hash-frontend/src/components/hooks/use-entity-by-id.ts @@ -14,10 +14,7 @@ import type { QueryEntitySubgraphQueryVariables, } from "../../graphql/api-types.gen"; import type { EntityRootType, Subgraph } from "@blockprotocol/graph"; -import type { - EntityTraversalPath, - GraphResolveDepths, -} from "@rust/hash-graph-store/types"; +import type { EntityTraversalPath, GraphResolveDepths } from "@rust/hash-graph-store/types"; export const useEntityById = ({ entityId, @@ -37,39 +34,39 @@ export const useEntityById = ({ permissions?: EntityPermissionsMap; } => { const [webId, entityUuid, draftId] = splitEntityId(entityId); - const { data, loading } = useQuery< - QueryEntitySubgraphQuery, - QueryEntitySubgraphQueryVariables - >(queryEntitySubgraphQuery, { - variables: { - request: { - filter: { - all: [ - { - equal: [{ path: ["webId"] }, { parameter: webId }], - }, - { - equal: [{ path: ["uuid"] }, { parameter: entityUuid }], - }, - ...(draftId - ? [ - { - equal: [{ path: ["draftId"] }, { parameter: draftId }], - }, - ] - : []), - ], + const { data, loading } = useQuery( + queryEntitySubgraphQuery, + { + variables: { + request: { + filter: { + all: [ + { + equal: [{ path: ["webId"] }, { parameter: webId }], + }, + { + equal: [{ path: ["uuid"] }, { parameter: entityUuid }], + }, + ...(draftId + ? [ + { + equal: [{ path: ["draftId"] }, { parameter: draftId }], + }, + ] + : []), + ], + }, + graphResolveDepths, + traversalPaths, + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts: !!draftId, + includePermissions, }, - graphResolveDepths, - traversalPaths, - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts: !!draftId, - includePermissions, }, + fetchPolicy: "cache-and-network", + pollInterval, }, - fetchPolicy: "cache-and-network", - pollInterval, - }); + ); return useMemo(() => { const response = data diff --git a/apps/hash-frontend/src/components/hooks/use-font-loaded-callback.ts b/apps/hash-frontend/src/components/hooks/use-font-loaded-callback.ts index bd7a2bb47b8..f3d70a0c361 100644 --- a/apps/hash-frontend/src/components/hooks/use-font-loaded-callback.ts +++ b/apps/hash-frontend/src/components/hooks/use-font-loaded-callback.ts @@ -3,10 +3,7 @@ import useFontFaceObserver from "use-font-face-observer"; import type { FontFace } from "use-font-face-observer"; -export const useFontLoadedCallback = ( - fontList: FontFace[], - callback?: () => void, -) => { +export const useFontLoadedCallback = (fontList: FontFace[], callback?: () => void) => { const isFontListLoaded = useFontFaceObserver(fontList); useLayoutEffect(() => { diff --git a/apps/hash-frontend/src/components/hooks/use-get-account-id-for-shortname.ts b/apps/hash-frontend/src/components/hooks/use-get-account-id-for-shortname.ts index 8db52515b97..05c21a533dd 100644 --- a/apps/hash-frontend/src/components/hooks/use-get-account-id-for-shortname.ts +++ b/apps/hash-frontend/src/components/hooks/use-get-account-id-for-shortname.ts @@ -15,22 +15,18 @@ export const useGetWebIdForShortname = ( const webId = useMemo(() => { /** @todo - don't do extract anymore */ - const userEntityId = users?.find((user) => user.shortname === shortname) - ?.entity.metadata.recordId.entityId; + const userEntityId = users?.find((user) => user.shortname === shortname)?.entity.metadata + .recordId.entityId; - const userWebId = userEntityId - ? extractWebIdFromEntityId(userEntityId) - : undefined; + const userWebId = userEntityId ? extractWebIdFromEntityId(userEntityId) : undefined; if (userWebId !== undefined) { return userWebId; } - const orgEntityId = orgs?.find((org) => org.shortname === shortname)?.entity - .metadata.recordId.entityId; - const orgWebId = orgEntityId - ? extractWebIdFromEntityId(orgEntityId) - : undefined; + const orgEntityId = orgs?.find((org) => org.shortname === shortname)?.entity.metadata.recordId + .entityId; + const orgWebId = orgEntityId ? extractWebIdFromEntityId(orgEntityId) : undefined; if (orgWebId !== undefined) { return orgWebId; diff --git a/apps/hash-frontend/src/components/hooks/use-get-block-protocol-blocks.ts b/apps/hash-frontend/src/components/hooks/use-get-block-protocol-blocks.ts index 289cfb485cd..f110281aa09 100644 --- a/apps/hash-frontend/src/components/hooks/use-get-block-protocol-blocks.ts +++ b/apps/hash-frontend/src/components/hooks/use-get-block-protocol-blocks.ts @@ -5,10 +5,7 @@ import { getBlockProtocolBlocksQuery } from "../../graphql/queries/block.queries import type { GetBlockProtocolBlocksQuery } from "../../graphql/api-types.gen"; export const useGetBlockProtocolBlocks = () => { - const { data, error } = useQuery( - getBlockProtocolBlocksQuery, - {}, - ); + const { data, error } = useQuery(getBlockProtocolBlocksQuery, {}); return { data, error }; }; diff --git a/apps/hash-frontend/src/components/hooks/use-get-owner-for-entity.ts b/apps/hash-frontend/src/components/hooks/use-get-owner-for-entity.ts index aec86da3c59..2911feaeb6d 100644 --- a/apps/hash-frontend/src/components/hooks/use-get-owner-for-entity.ts +++ b/apps/hash-frontend/src/components/hooks/use-get-owner-for-entity.ts @@ -22,10 +22,7 @@ export const useGetOwnerForEntity = () => { return useCallback( (params: { entityId: EntityId } | { webId: WebId }) => { - const webId = - "entityId" in params - ? extractWebIdFromEntityId(params.entityId) - : params.webId; + const webId = "entityId" in params ? extractWebIdFromEntityId(params.entityId) : params.webId; if (loading || !users?.length || !orgs?.length) { return { @@ -35,8 +32,7 @@ export const useGetOwnerForEntity = () => { } const owner = - users.find((user) => webId === user.accountId) ?? - orgs.find((org) => webId === org.webId); + users.find((user) => webId === user.accountId) ?? orgs.find((org) => webId === org.webId); if (!owner) { Sentry.captureException( diff --git a/apps/hash-frontend/src/components/hooks/use-hash-instance.ts b/apps/hash-frontend/src/components/hooks/use-hash-instance.ts index 490389729f2..3b263a142f5 100644 --- a/apps/hash-frontend/src/components/hooks/use-hash-instance.ts +++ b/apps/hash-frontend/src/components/hooks/use-hash-instance.ts @@ -29,9 +29,7 @@ export const useHashInstance = (): { const { hashInstanceSettings } = data ?? {}; - const hashInstance = useMemo< - Simplified> | undefined - >(() => { + const hashInstance = useMemo> | undefined>(() => { if (!hashInstanceSettings) { return undefined; } diff --git a/apps/hash-frontend/src/components/hooks/use-logout-flow.ts b/apps/hash-frontend/src/components/hooks/use-logout-flow.ts index 853e11a271e..4068dbf2734 100644 --- a/apps/hash-frontend/src/components/hooks/use-logout-flow.ts +++ b/apps/hash-frontend/src/components/hooks/use-logout-flow.ts @@ -26,8 +26,7 @@ export const useLogoutFlow = () => { * @todo: verify that the page is publicly viewable when pages aren't * publicly viewable by default */ - const isPubliclyViewablePage = - router.pathname === "/[shortname]/[page-slug]"; + const isPubliclyViewablePage = router.pathname === "/[shortname]/[page-slug]"; if (!isPubliclyViewablePage) { /** diff --git a/apps/hash-frontend/src/components/hooks/use-orgs-with-links.ts b/apps/hash-frontend/src/components/hooks/use-orgs-with-links.ts index e0b0fc8a92a..830f77ad52c 100644 --- a/apps/hash-frontend/src/components/hooks/use-orgs-with-links.ts +++ b/apps/hash-frontend/src/components/hooks/use-orgs-with-links.ts @@ -56,10 +56,9 @@ export const useOrgsWithLinks = ({ }, ] : []), - generateVersionedUrlMatchingFilter( - systemEntityTypes.organization.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.organization.entityTypeId, { + ignoreParents: true, + }), ], }, traversalPaths: [ @@ -110,9 +109,7 @@ export const useOrgsWithLinks = ({ return undefined; } - const subgraph = deserializeQueryEntitySubgraphResponse( - queryEntitySubgraphResponse, - ).subgraph; + const subgraph = deserializeQueryEntitySubgraphResponse(queryEntitySubgraphResponse).subgraph; return getRoots(subgraph).map((orgEntity) => { if (!isEntityOrgEntity(orgEntity)) { diff --git a/apps/hash-frontend/src/components/hooks/use-orgs.ts b/apps/hash-frontend/src/components/hooks/use-orgs.ts index b13dd7c970e..a6b115484dc 100644 --- a/apps/hash-frontend/src/components/hooks/use-orgs.ts +++ b/apps/hash-frontend/src/components/hooks/use-orgs.ts @@ -10,10 +10,7 @@ import { constructMinimalOrg, isEntityOrgEntity } from "../../lib/user-and-org"; import { entityHasEntityTypeByVersionedUrlFilter } from "../../shared/filters"; import { useMemoCompare } from "../../shared/use-memo-compare"; -import type { - QueryEntitiesQuery, - QueryEntitiesQueryVariables, -} from "../../graphql/api-types.gen"; +import type { QueryEntitiesQuery, QueryEntitiesQueryVariables } from "../../graphql/api-types.gen"; import type { MinimalOrg } from "../../lib/user-and-org"; import type { ApolloQueryResult } from "@apollo/client"; @@ -25,27 +22,25 @@ export const useOrgs = (): { orgs?: MinimalOrg[]; refetch: () => Promise>; } => { - const { data, loading, refetch } = useQuery< - QueryEntitiesQuery, - QueryEntitiesQueryVariables - >(queryEntitiesQuery, { - variables: { - request: { - filter: convertBpFilterToGraphFilter({ - filters: [ - entityHasEntityTypeByVersionedUrlFilter( - systemEntityTypes.organization.entityTypeId, - ), - ], - operator: "AND", - }), - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts: false, - includePermissions: false, + const { data, loading, refetch } = useQuery( + queryEntitiesQuery, + { + variables: { + request: { + filter: convertBpFilterToGraphFilter({ + filters: [ + entityHasEntityTypeByVersionedUrlFilter(systemEntityTypes.organization.entityTypeId), + ], + operator: "AND", + }), + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts: false, + includePermissions: false, + }, }, + fetchPolicy: "cache-and-network", }, - fetchPolicy: "cache-and-network", - }); + ); const { queryEntities } = data ?? {}; @@ -55,16 +50,14 @@ export const useOrgs = (): { return undefined; } - return deserializeQueryEntitiesResponse(queryEntities).entities.map( - (orgEntity) => { - if (!isEntityOrgEntity(orgEntity)) { - throw new Error( - `Entity with type(s) ${orgEntity.metadata.entityTypeIds.join(", ")} is not an org entity`, - ); - } - return constructMinimalOrg({ orgEntity }); - }, - ); + return deserializeQueryEntitiesResponse(queryEntities).entities.map((orgEntity) => { + if (!isEntityOrgEntity(orgEntity)) { + throw new Error( + `Entity with type(s) ${orgEntity.metadata.entityTypeIds.join(", ")} is not an org entity`, + ); + } + return constructMinimalOrg({ orgEntity }); + }); }, [queryEntities], /** diff --git a/apps/hash-frontend/src/components/hooks/use-page-comments.ts b/apps/hash-frontend/src/components/hooks/use-page-comments.ts index e329af1a249..04c9fd6ee70 100644 --- a/apps/hash-frontend/src/components/hooks/use-page-comments.ts +++ b/apps/hash-frontend/src/components/hooks/use-page-comments.ts @@ -8,11 +8,7 @@ import type { GetPageCommentsQuery, GetPageCommentsQueryVariables, } from "../../graphql/api-types.gen"; -import type { - EntityId, - EntityMetadata, - EntityTemporalMetadata, -} from "@blockprotocol/type-system"; +import type { EntityId, EntityMetadata, EntityTemporalMetadata } from "@blockprotocol/type-system"; import type { TextToken } from "@local/hash-isomorphic-utils/types"; export type PageThread = PageComment & { @@ -35,14 +31,14 @@ export type PageCommentsInfo = { const emptyComments: PageThread[] = []; export const usePageComments = (pageEntityId?: EntityId): PageCommentsInfo => { - const { data, loading } = useQuery< - GetPageCommentsQuery, - GetPageCommentsQueryVariables - >(getPageComments, { - variables: { entityId: pageEntityId! }, - pollInterval: 10_000, - skip: !pageEntityId, - }); + const { data, loading } = useQuery( + getPageComments, + { + variables: { entityId: pageEntityId! }, + pollInterval: 10_000, + skip: !pageEntityId, + }, + ); const pageComments = data?.pageComments; return { diff --git a/apps/hash-frontend/src/components/hooks/use-reorder-page.ts b/apps/hash-frontend/src/components/hooks/use-reorder-page.ts index 528d6f5fb52..fff78e48019 100644 --- a/apps/hash-frontend/src/components/hooks/use-reorder-page.ts +++ b/apps/hash-frontend/src/components/hooks/use-reorder-page.ts @@ -25,9 +25,7 @@ export const useReorderPage = () => { { query: queryEntitySubgraphQuery, variables: getAccountPagesVariables({ - webId: extractWebIdFromEntityId( - data.setParentPage.metadata.recordId.entityId, - ), + webId: extractWebIdFromEntityId(data.setParentPage.metadata.recordId.entityId), }), }, ] diff --git a/apps/hash-frontend/src/components/hooks/use-shortname-input.ts b/apps/hash-frontend/src/components/hooks/use-shortname-input.ts index f16ff9d49e9..84f237699b1 100644 --- a/apps/hash-frontend/src/components/hooks/use-shortname-input.ts +++ b/apps/hash-frontend/src/components/hooks/use-shortname-input.ts @@ -3,16 +3,9 @@ import { useCallback, useState } from "react"; import { isShortnameTaken as isShortnameTakenQuery } from "../../graphql/queries/user.queries"; -import type { - IsShortnameTakenQuery, - QueryIsShortnameTakenArgs, -} from "../../graphql/api-types.gen"; +import type { IsShortnameTakenQuery, QueryIsShortnameTakenArgs } from "../../graphql/api-types.gen"; -type ShortnameErrorCode = - | "IS_EMPTY" - | "IS_TOO_LONG" - | "IS_TOO_SHORT" - | "IS_TAKEN"; +type ShortnameErrorCode = "IS_EMPTY" | "IS_TOO_LONG" | "IS_TOO_SHORT" | "IS_TAKEN"; const getShortnameError = (error: string | undefined, isTouched: boolean) => { switch (error) { @@ -29,8 +22,7 @@ const getShortnameError = (error: string | undefined, isTouched: boolean) => { } }; -const parseShortnameInput = (input: string) => - input.replaceAll(/[^a-zA-Z0-9-_]/g, ""); +const parseShortnameInput = (input: string) => input.replaceAll(/[^a-zA-Z0-9-_]/g, ""); export const useShortnameInput = () => { const [loading, setLoading] = useState(false); @@ -47,10 +39,7 @@ export const useShortnameInput = () => { setLoading(true); - const { data } = await client.query< - IsShortnameTakenQuery, - QueryIsShortnameTakenArgs - >({ + const { data } = await client.query({ query: isShortnameTakenQuery, variables: { shortname, diff --git a/apps/hash-frontend/src/components/hooks/use-snackbar.ts b/apps/hash-frontend/src/components/hooks/use-snackbar.ts index 30475abda9a..9300276da50 100644 --- a/apps/hash-frontend/src/components/hooks/use-snackbar.ts +++ b/apps/hash-frontend/src/components/hooks/use-snackbar.ts @@ -19,27 +19,19 @@ type EnqueueWithoutVariant = ( type SnackbarVariants = Record; -const variantTypes: VariantType[] = [ - "default", - "error", - "info", - "success", - "warning", -]; +const variantTypes: VariantType[] = ["default", "error", "info", "success", "warning"]; -const generateSnackbarVariants = ( - enqueueSnackbar: ProviderContext["enqueueSnackbar"], -) => { +const generateSnackbarVariants = (enqueueSnackbar: ProviderContext["enqueueSnackbar"]) => { /** * we map a `EnqueueWithoutVariant` function to each variant, * which is `enqueueSnackbar`, but with a pre-defined `variant` * */ const entries = variantTypes.map( (variant) => - [ - variant, - (message, options) => enqueueSnackbar(message, { ...options, variant }), - ] as [VariantType, EnqueueWithoutVariant], + [variant, (message, options) => enqueueSnackbar(message, { ...options, variant })] as [ + VariantType, + EnqueueWithoutVariant, + ], ); /** we use entries to generate the object with `EnqueueWithoutVariant` function of each variant @@ -60,8 +52,5 @@ export const useSnackbar = (): SnackbarManager => { [enqueueSnackbar], ); - return useMemo( - () => ({ closeSnackbar, triggerSnackbar }), - [closeSnackbar, triggerSnackbar], - ); + return useMemo(() => ({ closeSnackbar, triggerSnackbar }), [closeSnackbar, triggerSnackbar]); }; diff --git a/apps/hash-frontend/src/components/hooks/use-update-authenticated-user.ts b/apps/hash-frontend/src/components/hooks/use-update-authenticated-user.ts index 6e1397596fe..cd461937a6b 100644 --- a/apps/hash-frontend/src/components/hooks/use-update-authenticated-user.ts +++ b/apps/hash-frontend/src/components/hooks/use-update-authenticated-user.ts @@ -41,10 +41,10 @@ export const useUpdateAuthenticatedUser = () => { fetchPolicy: "cache-and-network", }); - const [updateEntity] = useMutation< - UpdateEntityMutation, - UpdateEntityMutationVariables - >(updateEntityMutation, { errorPolicy: "all" }); + const [updateEntity] = useMutation( + updateEntityMutation, + { errorPolicy: "all" }, + ); const [loading, setLoading] = useState(false); @@ -68,9 +68,7 @@ export const useUpdateAuthenticatedUser = () => { const latestUserEntitySubgraph = await getMe() .then(({ data }) => { const subgraph = data - ? mapGqlSubgraphFieldsFragmentToSubgraph< - EntityRootType - >(data.me.subgraph) + ? mapGqlSubgraphFieldsFragmentToSubgraph>(data.me.subgraph) : undefined; return subgraph; @@ -78,9 +76,7 @@ export const useUpdateAuthenticatedUser = () => { .catch(() => undefined); if (!latestUserEntitySubgraph) { - throw new Error( - "Could not get latest user entity when updating the authenticated user.", - ); + throw new Error("Could not get latest user entity when updating the authenticated user."); } const latestUserEntity = getRoots(latestUserEntitySubgraph)[0]!; diff --git a/apps/hash-frontend/src/components/hooks/use-update-page-title.ts b/apps/hash-frontend/src/components/hooks/use-update-page-title.ts index b33899dcc6c..e3e42e54c66 100644 --- a/apps/hash-frontend/src/components/hooks/use-update-page-title.ts +++ b/apps/hash-frontend/src/components/hooks/use-update-page-title.ts @@ -4,10 +4,7 @@ import { useCallback } from "react"; import { updatePage } from "../../graphql/queries/page.queries"; import { useGetPageRefetchQueries } from "./shared/get-page-refetch-queries"; -import type { - UpdatePageMutation, - UpdatePageMutationVariables, -} from "../../graphql/api-types.gen"; +import type { UpdatePageMutation, UpdatePageMutationVariables } from "../../graphql/api-types.gen"; import type { EntityId } from "@blockprotocol/type-system"; export const useUpdatePageTitle = () => { diff --git a/apps/hash-frontend/src/components/hooks/use-user-or-org-shortname-by-owned-by-id.ts b/apps/hash-frontend/src/components/hooks/use-user-or-org-shortname-by-owned-by-id.ts index 36aa21f3824..824f0fbc76f 100644 --- a/apps/hash-frontend/src/components/hooks/use-user-or-org-shortname-by-owned-by-id.ts +++ b/apps/hash-frontend/src/components/hooks/use-user-or-org-shortname-by-owned-by-id.ts @@ -6,9 +6,7 @@ import { useUserOrOrg } from "../../shared/use-user-or-org"; import type { WebId } from "@blockprotocol/type-system"; -export const useUserOrOrgShortnameByWebId = (params: { - webId: WebId | null; -}) => { +export const useUserOrOrgShortnameByWebId = (params: { webId: WebId | null }) => { const { webId } = params; const { userOrOrg, loading } = useUserOrOrg({ diff --git a/apps/hash-frontend/src/components/hooks/use-users-with-links.ts b/apps/hash-frontend/src/components/hooks/use-users-with-links.ts index b24c71c2be4..0b4f1605ba2 100644 --- a/apps/hash-frontend/src/components/hooks/use-users-with-links.ts +++ b/apps/hash-frontend/src/components/hooks/use-users-with-links.ts @@ -54,10 +54,9 @@ export const useUsersWithLinks = ({ }, ] : []), - generateVersionedUrlMatchingFilter( - systemEntityTypes.user.entityTypeId, - { ignoreParents: true }, - ), + generateVersionedUrlMatchingFilter(systemEntityTypes.user.entityTypeId, { + ignoreParents: true, + }), ], }, traversalPaths: [ diff --git a/apps/hash-frontend/src/components/hooks/use-users.ts b/apps/hash-frontend/src/components/hooks/use-users.ts index 788a104b3c4..81f6928df12 100644 --- a/apps/hash-frontend/src/components/hooks/use-users.ts +++ b/apps/hash-frontend/src/components/hooks/use-users.ts @@ -6,17 +6,11 @@ import { currentTimeInstantTemporalAxes } from "@local/hash-isomorphic-utils/gra import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids"; import { queryEntitiesQuery } from "../../graphql/queries/knowledge/entity.queries"; -import { - constructMinimalUser, - isEntityUserEntity, -} from "../../lib/user-and-org"; +import { constructMinimalUser, isEntityUserEntity } from "../../lib/user-and-org"; import { entityHasEntityTypeByVersionedUrlFilter } from "../../shared/filters"; import { useMemoCompare } from "../../shared/use-memo-compare"; -import type { - QueryEntitiesQuery, - QueryEntitiesQueryVariables, -} from "../../graphql/api-types.gen"; +import type { QueryEntitiesQuery, QueryEntitiesQueryVariables } from "../../graphql/api-types.gen"; import type { MinimalUser } from "../../lib/user-and-org"; export const useUsers = (): { @@ -24,27 +18,23 @@ export const useUsers = (): { refetch: () => void; users?: MinimalUser[]; } => { - const { data, loading, refetch } = useQuery< - QueryEntitiesQuery, - QueryEntitiesQueryVariables - >(queryEntitiesQuery, { - variables: { - request: { - filter: convertBpFilterToGraphFilter({ - filters: [ - entityHasEntityTypeByVersionedUrlFilter( - systemEntityTypes.user.entityTypeId, - ), - ], - operator: "AND", - }), - temporalAxes: currentTimeInstantTemporalAxes, - includeDrafts: false, - includePermissions: false, + const { data, loading, refetch } = useQuery( + queryEntitiesQuery, + { + variables: { + request: { + filter: convertBpFilterToGraphFilter({ + filters: [entityHasEntityTypeByVersionedUrlFilter(systemEntityTypes.user.entityTypeId)], + operator: "AND", + }), + temporalAxes: currentTimeInstantTemporalAxes, + includeDrafts: false, + includePermissions: false, + }, }, + fetchPolicy: "cache-and-network", }, - fetchPolicy: "cache-and-network", - }); + ); const { queryEntities } = data ?? {}; @@ -54,17 +44,15 @@ export const useUsers = (): { return undefined; } - return deserializeQueryEntitiesResponse(queryEntities).entities.map( - (userEntity) => { - if (!isEntityUserEntity(userEntity)) { - throw new Error( - `Entity with type(s) ${userEntity.metadata.entityTypeIds.join(", ")} is not a user entity`, - ); - } + return deserializeQueryEntitiesResponse(queryEntities).entities.map((userEntity) => { + if (!isEntityUserEntity(userEntity)) { + throw new Error( + `Entity with type(s) ${userEntity.metadata.entityTypeIds.join(", ")} is not a user entity`, + ); + } - return constructMinimalUser({ userEntity }); - }, - ); + return constructMinimalUser({ userEntity }); + }); }, [queryEntities], /** diff --git a/apps/hash-frontend/src/components/page-icon.tsx b/apps/hash-frontend/src/components/page-icon.tsx index 56d3e6eb7a0..02f1af6523c 100644 --- a/apps/hash-frontend/src/components/page-icon.tsx +++ b/apps/hash-frontend/src/components/page-icon.tsx @@ -16,12 +16,7 @@ interface PageIconProps { sx?: BoxProps["sx"]; } -export const PageIcon = ({ - isCanvas, - icon, - size = "medium", - sx = [], -}: PageIconProps) => { +export const PageIcon = ({ isCanvas, icon, size = "medium", sx = [] }: PageIconProps) => { const sizes = iconVariantSizes[size]; return ( diff --git a/apps/hash-frontend/src/components/remote-block/add-linked-query-prompt.tsx b/apps/hash-frontend/src/components/remote-block/add-linked-query-prompt.tsx index 6092e9e3a28..1ebc86370b8 100644 --- a/apps/hash-frontend/src/components/remote-block/add-linked-query-prompt.tsx +++ b/apps/hash-frontend/src/components/remote-block/add-linked-query-prompt.tsx @@ -37,14 +37,10 @@ export const AddLinkedQueryPrompt: FunctionComponent<{ /> ) : null} - The {blockName.toLowerCase()} block needs to know what - information to display + The {blockName.toLowerCase()} block needs to know what information to + display - diff --git a/apps/hash-frontend/src/components/remote-block/block-renderer.tsx b/apps/hash-frontend/src/components/remote-block/block-renderer.tsx index 5fc10433e23..7abce1c74d2 100644 --- a/apps/hash-frontend/src/components/remote-block/block-renderer.tsx +++ b/apps/hash-frontend/src/components/remote-block/block-renderer.tsx @@ -30,18 +30,13 @@ export const BlockRenderer: FunctionComponent = ({ } return ; } else if (entryPoint === "custom-element") { - if ( - typeof blockSource === "string" || - !(blockSource.prototype instanceof HTMLElement) - ) { + if (typeof blockSource === "string" || !(blockSource.prototype instanceof HTMLElement)) { throw new Error( `'custom-element' entryPoint expects parsed source to have 'HTMLElement' as prototype`, ); } if (typeof blockType.tagName !== "string") { - throw new Error( - `Must provide blockType.tagName when entryPoint is 'custom-element'`, - ); + throw new Error(`Must provide blockType.tagName when entryPoint is 'custom-element'`); } return ( = ({ elementClass, properties, tagName }) => { - const [CustomElement, setCustomElement] = useState( - null, - ); +export const CustomElementLoader: FunctionComponent = ({ + elementClass, + properties, + tagName, +}) => { + const [CustomElement, setCustomElement] = useState(null); const existingDefinitionRef = useRef(null); useLayoutEffect(() => { @@ -33,9 +33,7 @@ export const CustomElementLoader: FunctionComponent< customElements.define(tagName, elementClass); } catch (err) { // eslint-disable-next-line no-console -- TODO: consider using logger - console.error( - `Error defining custom element: ${(err as Error).message}`, - ); + console.error(`Error defining custom element: ${(err as Error).message}`); throw err; } } else if (existingCustomElement !== elementClass) { @@ -53,9 +51,7 @@ export const CustomElementLoader: FunctionComponent< customElements.define(`${tagName}${i}`, elementClass); } catch (err) { // eslint-disable-next-line no-console -- TODO: consider using logger - console.error( - `Error defining custom element: ${(err as Error).message}`, - ); + console.error(`Error defining custom element: ${(err as Error).message}`); throw err; } } diff --git a/apps/hash-frontend/src/components/remote-block/block-renderer/html.tsx b/apps/hash-frontend/src/components/remote-block/block-renderer/html.tsx index a5817feb0c7..2ce919e2d93 100644 --- a/apps/hash-frontend/src/components/remote-block/block-renderer/html.tsx +++ b/apps/hash-frontend/src/components/remote-block/block-renderer/html.tsx @@ -9,9 +9,7 @@ type HtmlElementLoaderProps = { html: HtmlBlockDefinition; }; -export const HtmlLoader: FunctionComponent = ({ - html, -}) => { +export const HtmlLoader: FunctionComponent = ({ html }) => { const ref = useRef(null); const [, setError] = useState(); diff --git a/apps/hash-frontend/src/components/remote-block/construct-service-module-callbacks.ts b/apps/hash-frontend/src/components/remote-block/construct-service-module-callbacks.ts index 9fbbde35e05..ee28df16b50 100644 --- a/apps/hash-frontend/src/components/remote-block/construct-service-module-callbacks.ts +++ b/apps/hash-frontend/src/components/remote-block/construct-service-module-callbacks.ts @@ -2,8 +2,7 @@ import { apiOrigin } from "@local/hash-isomorphic-utils/environment"; import type { ServiceEmbedderMessageCallbacks } from "@blockprotocol/service"; -type ServiceFunction = - ServiceEmbedderMessageCallbacks[keyof ServiceEmbedderMessageCallbacks]; +type ServiceFunction = ServiceEmbedderMessageCallbacks[keyof ServiceEmbedderMessageCallbacks]; const callExternalApiMethod = async (params: { providerName: string; diff --git a/apps/hash-frontend/src/components/remote-block/load-remote-block.ts b/apps/hash-frontend/src/components/remote-block/load-remote-block.ts index 983b567b711..d58cb4ddc3e 100644 --- a/apps/hash-frontend/src/components/remote-block/load-remote-block.ts +++ b/apps/hash-frontend/src/components/remote-block/load-remote-block.ts @@ -4,15 +4,9 @@ import { crossFrameFetchFn } from "../sandbox/framed-block/util"; import type { ReactElement } from "react"; -export type UnknownBlock = - | string - | typeof HTMLElement - | ((...props: unknown[]) => ReactElement); +export type UnknownBlock = string | typeof HTMLElement | ((...props: unknown[]) => ReactElement); -export type FetchSourceFn = ( - url: string, - signal?: AbortSignal, -) => Promise; +export type FetchSourceFn = (url: string, signal?: AbortSignal) => Promise; /** * Adapted from https://github.com/Paciolan/remote-module-loader @@ -20,9 +14,7 @@ export type FetchSourceFn = ( const requires = (name: string) => { if (!(name in blockDependencies)) { - throw new Error( - `Could not require '${name}'. '${name}' does not exist in dependencies.`, - ); + throw new Error(`Could not require '${name}'. '${name}' does not exist in dependencies.`); } return blockDependencies[name]; @@ -33,10 +25,7 @@ const defaultFetchFn: FetchSourceFn = (url, signal) => type FetchAndParseFn = ( fetchSourceFn: FetchSourceFn, -) => ( - url: string, - signal?: AbortSignal, -) => Promise>; +) => (url: string, signal?: AbortSignal) => Promise>; const fetchAndParseBlock: FetchAndParseFn = (fetchSourceFn) => (url, signal) => fetchSourceFn(url, signal).then((source) => { @@ -67,9 +56,7 @@ const fetchAndParseBlock: FetchAndParseFn = (fetchSourceFn) => (url, signal) => return module.exports; }); -export const loadRemoteBlock = memoizeFetchFunction( - fetchAndParseBlock(defaultFetchFn), -); +export const loadRemoteBlock = memoizeFetchFunction(fetchAndParseBlock(defaultFetchFn)); export const loadCrossFrameRemoteBlock = memoizeFetchFunction( fetchAndParseBlock(crossFrameFetchFn), diff --git a/apps/hash-frontend/src/components/remote-block/remote-block.tsx b/apps/hash-frontend/src/components/remote-block/remote-block.tsx index da288c150d5..aabe3047277 100644 --- a/apps/hash-frontend/src/components/remote-block/remote-block.tsx +++ b/apps/hash-frontend/src/components/remote-block/remote-block.tsx @@ -3,10 +3,7 @@ import { useEffect, useMemo, useRef } from "react"; import { v4 as uuid } from "uuid"; import { useGraphEmbedderModule } from "@blockprotocol/graph/react"; -import { - getOutgoingLinksForEntity, - getRoots, -} from "@blockprotocol/graph/stdlib"; +import { getOutgoingLinksForEntity, getRoots } from "@blockprotocol/graph/stdlib"; import { useHookEmbedderModule } from "@blockprotocol/hook/react"; import { useServiceEmbedderModule } from "@blockprotocol/service/react"; import { textualContentPropertyTypeBaseUrl } from "@local/hash-isomorphic-utils/entity-store"; @@ -69,10 +66,7 @@ export const BlockLoadingIndicator: FunctionComponent<{ ); @@ -161,17 +155,15 @@ export const RemoteBlock: FunctionComponent = ({ const blockSchema = useMemo(() => { const blockSchemaId = blockMetadata.schema; - return Object.values(userBlocks).find( - ({ schema }) => schema && schema.$id === blockSchemaId, - )?.schema; + return Object.values(userBlocks).find(({ schema }) => schema && schema.$id === blockSchemaId) + ?.schema; }, [userBlocks, blockMetadata]); const blockSchemaRequiresOutgoingHasQueryLinks = useMemo(() => { if (blockSchema) { return Object.entries(blockSchema.links ?? {}).some( ([linkEntityTypeId, value]) => - linkEntityTypeId === - blockProtocolLinkEntityTypes.hasQuery.linkEntityTypeId && + linkEntityTypeId === blockProtocolLinkEntityTypes.hasQuery.linkEntityTypeId && value.minItems && value.minItems > 0, ); @@ -182,9 +174,7 @@ export const RemoteBlock: FunctionComponent = ({ const blockHasMissingHasQueryLinks = useMemo(() => { if (blockSchemaRequiresOutgoingHasQueryLinks) { - const blockEntity = getRoots( - graphProperties.blockEntitySubgraph, - )[0]; + const blockEntity = getRoots(graphProperties.blockEntitySubgraph)[0]; if (blockEntity) { const outgoingLinks = getOutgoingLinksForEntity( diff --git a/apps/hash-frontend/src/components/remote-block/use-remote-block.ts b/apps/hash-frontend/src/components/remote-block/use-remote-block.ts index 88373802e55..4c0d423e764 100644 --- a/apps/hash-frontend/src/components/remote-block/use-remote-block.ts +++ b/apps/hash-frontend/src/components/remote-block/use-remote-block.ts @@ -1,9 +1,6 @@ import { useEffect, useRef, useState } from "react"; -import { - loadCrossFrameRemoteBlock, - loadRemoteBlock, -} from "./load-remote-block"; +import { loadCrossFrameRemoteBlock, loadRemoteBlock } from "./load-remote-block"; import { isTopWindow } from "./util"; import type { UnknownBlock } from "./load-remote-block"; @@ -26,14 +23,8 @@ type UseRemoteComponentState = { // @todo put this in context const remoteModuleCache: Record = {}; -export const loadBlockComponent = ( - sourceUrl: string, - crossFrame = false, - signal?: AbortSignal, -) => { - const blockLoaderFn = crossFrame - ? loadCrossFrameRemoteBlock - : loadRemoteBlock; +export const loadBlockComponent = (sourceUrl: string, crossFrame = false, signal?: AbortSignal) => { + const blockLoaderFn = crossFrame ? loadCrossFrameRemoteBlock : loadRemoteBlock; return blockLoaderFn(sourceUrl, signal).then((module) => { remoteModuleCache[sourceUrl] = { @@ -50,26 +41,21 @@ export const loadBlockComponent = ( /** * @see https://github.com/Paciolan/remote-component/blob/master/src/hooks/useRemoteComponent.ts */ -export const useRemoteBlock: UseRemoteBlockHook = ( - url, - crossFrame, - onBlockLoaded, -) => { +export const useRemoteBlock: UseRemoteBlockHook = (url, crossFrame, onBlockLoaded) => { if (crossFrame && isTopWindow()) { throw new Error( "crossFrame passed to useRemoteBlock from top window. This should be set from framed windows only.", ); } - const [{ loading, err, component, url: loadedUrl }, setState] = - useState( - remoteModuleCache[url] ?? { - loading: true, - err: undefined, - component: undefined, - url: null, - }, - ); + const [{ loading, err, component, url: loadedUrl }, setState] = useState( + remoteModuleCache[url] ?? { + loading: true, + err: undefined, + component: undefined, + url: null, + }, + ); useEffect(() => { if (!loading && !err) { diff --git a/apps/hash-frontend/src/components/sandbox/block-framer/block-framer.tsx b/apps/hash-frontend/src/components/sandbox/block-framer/block-framer.tsx index bbb38c2f355..d56cee98140 100644 --- a/apps/hash-frontend/src/components/sandbox/block-framer/block-framer.tsx +++ b/apps/hash-frontend/src/components/sandbox/block-framer/block-framer.tsx @@ -17,9 +17,7 @@ export type CrossFrameProxyProps = GraphEmbedderMessageCallbacks & { onBlockLoaded: () => void; }; -const fetchSource = memoizeFetchFunction((url) => - fetch(url).then((resp) => resp.text()), -); +const fetchSource = memoizeFetchFunction((url) => fetch(url).then((resp) => resp.text())); export const BlockFramer: FunctionComponent = ({ sourceUrl, @@ -127,10 +125,7 @@ export const BlockFramer: FunctionComponent = ({ ); useEffect(() => { - const msgHandler = ({ - data, - source, - }: MessageEvent) => { + const msgHandler = ({ data, source }: MessageEvent) => { if (source !== frameRef.current?.contentWindow) { return; } diff --git a/apps/hash-frontend/src/components/sandbox/framed-block/framed-block.tsx b/apps/hash-frontend/src/components/sandbox/framed-block/framed-block.tsx index e7bfb851d83..f278ab8782d 100644 --- a/apps/hash-frontend/src/components/sandbox/framed-block/framed-block.tsx +++ b/apps/hash-frontend/src/components/sandbox/framed-block/framed-block.tsx @@ -23,16 +23,11 @@ export const FramedBlock: FunctionComponent = () => { const initialData = properties ? JSON.parse(properties) : undefined; - const [blockProperties, setBlockProperties] = useState( - initialData, - ); + const [blockProperties, setBlockProperties] = useState(initialData); const _beforeCapture = useCallback( (scope: Sentry.Scope) => { - scope.setTag( - "block", - blockProperties?.metadata.recordId.entityId as string, - ); + scope.setTag("block", blockProperties?.metadata.recordId.entityId as string); }, [blockProperties], ); @@ -77,33 +72,26 @@ export const FramedBlock: FunctionComponent = () => { * @todo set loading / error states based on promise status and pass into block. * in order to provide aggregateLoading, aggregateError, etc */ - const queryEntities: GraphEmbedderMessageCallbacks["queryEntities"] = ( - ...payload - ) => + const queryEntities: GraphEmbedderMessageCallbacks["queryEntities"] = (...payload) => sendMessage({ payload, type: "queryEntities", }); - const queryEntityTypes: GraphEmbedderMessageCallbacks["queryEntityTypes"] = ( - ...payload - ) => + const queryEntityTypes: GraphEmbedderMessageCallbacks["queryEntityTypes"] = (...payload) => sendMessage({ payload, type: "queryEntityTypes", }); - const createEntity: GraphEmbedderMessageCallbacks["createEntity"] = ( - ...payload - ) => + const createEntity: GraphEmbedderMessageCallbacks["createEntity"] = (...payload) => sendMessage({ payload, type: "createEntity", }); - const updateEntity: GraphEmbedderMessageCallbacks["updateEntity"] = ( - ...payload - ) => sendMessage({ payload, type: "updateEntity" }); + const updateEntity: GraphEmbedderMessageCallbacks["updateEntity"] = (...payload) => + sendMessage({ payload, type: "updateEntity" }); const getEmbedBlock: FetchEmbedCodeFn = (...payload) => sendMessage({ payload, type: "getEmbedBlock" }); diff --git a/apps/hash-frontend/src/components/sandbox/framed-block/util.ts b/apps/hash-frontend/src/components/sandbox/framed-block/util.ts index 77e15b5561c..93be5d3d72d 100644 --- a/apps/hash-frontend/src/components/sandbox/framed-block/util.ts +++ b/apps/hash-frontend/src/components/sandbox/framed-block/util.ts @@ -22,11 +22,7 @@ export function sendMessage( const timeout = 10_000; setTimeout(() => { reject( - new Error( - `Cross-frame request ${requestId} unresolved in ${ - timeout / 1000 - } seconds.`, - ), + new Error(`Cross-frame request ${requestId} unresolved in ${timeout / 1000} seconds.`), ); }, timeout); }); diff --git a/apps/hash-frontend/src/components/sandbox/resizing-iframe/resizing-iframe.tsx b/apps/hash-frontend/src/components/sandbox/resizing-iframe/resizing-iframe.tsx index c9bff4cd4ac..f93a8def703 100644 --- a/apps/hash-frontend/src/components/sandbox/resizing-iframe/resizing-iframe.tsx +++ b/apps/hash-frontend/src/components/sandbox/resizing-iframe/resizing-iframe.tsx @@ -26,44 +26,43 @@ type ResizingIFrameProps = DetailedHTMLProps< children?: undefined; }; -export const ResizingIFrame = forwardRef< - HTMLIFrameElement, - ResizingIFrameProps ->((props, iFrameRef) => { - useEffect(() => { - if (typeof iFrameRef === "function") { - throw new Error("Ref must be an object, not a function."); - } +export const ResizingIFrame = forwardRef( + (props, iFrameRef) => { + useEffect(() => { + if (typeof iFrameRef === "function") { + throw new Error("Ref must be an object, not a function."); + } - const iframe = iFrameRef?.current; - if (!iframe) { - throw new Error("iFrame not loaded."); - } + const iframe = iFrameRef?.current; + if (!iframe) { + throw new Error("iFrame not loaded."); + } - /** - * @todo see if anything else to be done about unresponsive frame warnings. - * fix the library types to include this valid option. - * @todo check origin for only the sandbox origin, once we have a way of setting it - * */ - iFrameResizer( - { - checkOrigin: false, - // @ts-expect-error -- warningTimeout needs to be added to the list of know attributes - warningTimeout: 20_000, - }, - iframe, - ); + /** + * @todo see if anything else to be done about unresponsive frame warnings. + * fix the library types to include this valid option. + * @todo check origin for only the sandbox origin, once we have a way of setting it + * */ + iFrameResizer( + { + checkOrigin: false, + // @ts-expect-error -- warningTimeout needs to be added to the list of know attributes + warningTimeout: 20_000, + }, + iframe, + ); - return () => (iframe as IFrameWithResizer).iFrameResizer.removeListeners(); - }, [iFrameRef, props]); + return () => (iframe as IFrameWithResizer).iFrameResizer.removeListeners(); + }, [iFrameRef, props]); - return ( -