From 6be32bea4c77f21532ffbaa8f77707f98283649e Mon Sep 17 00:00:00 2001 From: Kyle Corbitt Date: Tue, 1 Aug 2023 21:01:05 -0700 Subject: [PATCH] Add debug modal for output cells See the actual input that a model got for a specific cell. The formatting isn't great right now; should probably iterate on that. --- package.json | 5 +- pnpm-lock.yaml | 92 +++++++++++++--- .../OutputsTable/OutputCell/CellContent.tsx | 19 ---- .../OutputsTable/OutputCell/CellOptions.tsx | 37 ------- .../OutputsTable/OutputCell/OutputCell.tsx | 103 ++++++++---------- .../OutputsTable/OutputCell/PromptModal.tsx | 36 ++++++ .../OutputsTable/OutputCell/TopActions.tsx | 53 +++++++++ .../OutputsTable/ScenarioEditor.tsx | 93 +++++++--------- .../OutputsTable/ScenarioEditorModal.tsx | 11 +- src/components/OutputsTable/ScenarioRow.tsx | 7 +- .../openai-ChatCompletion/getCompletion.ts | 17 ++- src/pages/api/experiments/og-image.tsx | 2 +- src/pages/world-champs/signup.tsx | 6 +- src/server/api/routers/worldChamps.router.ts | 2 +- src/server/utils/deriveNewContructFn.ts | 4 +- src/theme/ChakraThemeProvider.tsx | 14 +++ 16 files changed, 295 insertions(+), 206 deletions(-) delete mode 100644 src/components/OutputsTable/OutputCell/CellContent.tsx delete mode 100644 src/components/OutputsTable/OutputCell/CellOptions.tsx create mode 100644 src/components/OutputsTable/OutputCell/PromptModal.tsx create mode 100644 src/components/OutputsTable/OutputCell/TopActions.tsx diff --git a/package.json b/package.json index 01fd446..8cc220c 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,10 @@ "@apidevtools/json-schema-ref-parser": "^10.1.0", "@babel/preset-typescript": "^7.22.5", "@babel/standalone": "^7.22.9", + "@chakra-ui/anatomy": "^2.2.0", "@chakra-ui/next-js": "^2.1.4", "@chakra-ui/react": "^2.7.1", + "@chakra-ui/styled-system": "^2.9.1", "@emotion/react": "^11.11.1", "@emotion/server": "^11.11.0", "@emotion/styled": "^11.11.0", @@ -63,7 +65,7 @@ "next-auth": "^4.22.1", "next-query-params": "^4.2.3", "nextjs-routes": "^2.0.1", - "openai": "4.0.0-beta.2", + "openai": "4.0.0-beta.7", "pluralize": "^8.0.0", "posthog-js": "^1.68.4", "prettier": "^3.0.0", @@ -72,6 +74,7 @@ "react-diff-viewer": "^3.1.1", "react-dom": "18.2.0", "react-icons": "^4.10.1", + "react-json-tree": "^0.18.0", "react-select": "^5.7.4", "react-syntax-highlighter": "^15.5.0", "react-textarea-autosize": "^8.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98ccc43..336c987 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,12 +17,18 @@ dependencies: '@babel/standalone': specifier: ^7.22.9 version: 7.22.9 + '@chakra-ui/anatomy': + specifier: ^2.2.0 + version: 2.2.0 '@chakra-ui/next-js': specifier: ^2.1.4 version: 2.1.4(@chakra-ui/react@2.7.1)(@emotion/react@11.11.1)(next@13.4.2)(react@18.2.0) '@chakra-ui/react': specifier: ^2.7.1 version: 2.7.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.6)(framer-motion@10.12.17)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/styled-system': + specifier: ^2.9.1 + version: 2.9.1 '@emotion/react': specifier: ^11.11.1 version: 11.11.1(@types/react@18.2.6)(react@18.2.0) @@ -132,8 +138,8 @@ dependencies: specifier: ^2.0.1 version: 2.0.1(next@13.4.2) openai: - specifier: 4.0.0-beta.2 - version: 4.0.0-beta.2 + specifier: 4.0.0-beta.7 + version: 4.0.0-beta.7 pluralize: specifier: ^8.0.0 version: 8.0.0 @@ -158,6 +164,9 @@ dependencies: react-icons: specifier: ^4.10.1 version: 4.10.1(react@18.2.0) + react-json-tree: + specifier: ^0.18.0 + version: 0.18.0(@types/react@18.2.6)(react@18.2.0) react-select: specifier: ^5.7.4 version: 5.7.4(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0) @@ -686,6 +695,10 @@ packages: resolution: {integrity: sha512-pKfOS/mztc4sUXHNc8ypJ1gPWSolWT770jrgVRfolVbYlki8y5Y+As996zMF6k5lewTu6j9DQequ7Cc9a69IVQ==} dev: false + /@chakra-ui/anatomy@2.2.0: + resolution: {integrity: sha512-cD8Ms5C8+dFda0LrORMdxiFhAZwOIY1BSlCadz6/mHUIgNdQy13AHPrXiq6qWdMslqVHq10k5zH7xMPLt6kjFg==} + dev: false + /@chakra-ui/avatar@2.2.11(@chakra-ui/system@2.5.8)(react@18.2.0): resolution: {integrity: sha512-CJFkoWvlCTDJTUBrKA/aVyG5Zz6TBEIVmmsJtqC6VcQuVDTxkWod8ruXnjb0LT2DUveL7xR5qZM9a5IXcsH3zg==} peerDependencies: @@ -2831,6 +2844,10 @@ packages: '@babel/types': 7.22.5 dev: true + /@types/base16@1.0.2: + resolution: {integrity: sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg==} + dev: false + /@types/body-parser@1.19.2: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: @@ -3013,6 +3030,7 @@ packages: /@types/qs@6.9.7: resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} + dev: true /@types/range-parser@1.2.4: resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} @@ -3658,6 +3676,10 @@ packages: resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==} dev: false + /base16@1.0.0: + resolution: {integrity: sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==} + dev: false + /base64-js@0.0.8: resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} engines: {node: '>= 0.4'} @@ -3916,10 +3938,24 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + /color2k@2.0.2: resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==} dev: false + /color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + dev: false + /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -5536,6 +5572,10 @@ packages: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: false + /is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: @@ -5910,6 +5950,10 @@ packages: resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} dev: false + /lodash.curry@4.1.1: + resolution: {integrity: sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==} + dev: false + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -6387,19 +6431,17 @@ packages: is-wsl: 2.2.0 dev: true - /openai@4.0.0-beta.2: - resolution: {integrity: sha512-zTuAxBFe5nSO7LngbV+/O0udtgHWfXb2lFei8/sDY4GB5cOdnrRoSOtiyUfV65ANdvlI4F75oYZX7w067cxj3w==} + /openai@4.0.0-beta.7: + resolution: {integrity: sha512-jHjwvpMuGkNxiQ3erwLZsOvPEhcVrMtwtfNeYmGCjhbdB+oStVw/7pIhIPkualu8rlhLwgMR7awknIaN3IQcOA==} dependencies: '@types/node': 18.16.0 '@types/node-fetch': 2.6.4 - '@types/qs': 6.9.7 abort-controller: 3.0.0 agentkeepalive: 4.3.0 digest-fetch: 1.3.0 form-data-encoder: 1.7.2 formdata-node: 4.4.1 node-fetch: 2.6.12 - qs: 6.11.2 transitivePeerDependencies: - encoding - supports-color @@ -6832,13 +6874,6 @@ packages: side-channel: 1.0.4 dev: false - /qs@6.11.2: - resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} - engines: {node: '>=0.6'} - dependencies: - side-channel: 1.0.4 - dev: false - /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -6875,6 +6910,18 @@ packages: webpack: 5.88.2 dev: true + /react-base16-styling@0.9.1: + resolution: {integrity: sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==} + dependencies: + '@babel/runtime': 7.22.6 + '@types/base16': 1.0.2 + '@types/lodash': 4.14.195 + base16: 1.0.0 + color: 3.2.1 + csstype: 3.1.2 + lodash.curry: 4.1.1 + dev: false + /react-clientside-effect@1.2.6(react@18.2.0): resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==} peerDependencies: @@ -6949,6 +6996,19 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: true + /react-json-tree@0.18.0(@types/react@18.2.6)(react@18.2.0): + resolution: {integrity: sha512-Qe6HKSXrr++n9Y31nkRJ3XvQMATISpqigH1vEKhLwB56+nk5thTP0ITThpjxY6ZG/ubpVq/aEHIcyLP/OPHxeA==} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': 7.22.6 + '@types/lodash': 4.14.195 + '@types/react': 18.2.6 + react: 18.2.0 + react-base16-styling: 0.9.1 + dev: false + /react-remove-scroll-bar@2.3.4(@types/react@18.2.6)(react@18.2.0): resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} engines: {node: '>=10'} @@ -7360,6 +7420,12 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} diff --git a/src/components/OutputsTable/OutputCell/CellContent.tsx b/src/components/OutputsTable/OutputCell/CellContent.tsx deleted file mode 100644 index 98b2388..0000000 --- a/src/components/OutputsTable/OutputCell/CellContent.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { type StackProps, VStack } from "@chakra-ui/react"; -import { CellOptions } from "./CellOptions"; - -export const CellContent = ({ - hardRefetch, - hardRefetching, - children, - ...props -}: { - hardRefetch: () => void; - hardRefetching: boolean; -} & StackProps) => ( - - - - {children} - - -); diff --git a/src/components/OutputsTable/OutputCell/CellOptions.tsx b/src/components/OutputsTable/OutputCell/CellOptions.tsx deleted file mode 100644 index dfdd139..0000000 --- a/src/components/OutputsTable/OutputCell/CellOptions.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Button, HStack, Icon, Spinner, Tooltip } from "@chakra-ui/react"; -import { BsArrowClockwise } from "react-icons/bs"; -import { useExperimentAccess } from "~/utils/hooks"; - -export const CellOptions = ({ - refetchingOutput, - refetchOutput, -}: { - refetchingOutput: boolean; - refetchOutput: () => void; -}) => { - const { canModify } = useExperimentAccess(); - return ( - - {canModify && ( - - - - )} - - ); -}; diff --git a/src/components/OutputsTable/OutputCell/OutputCell.tsx b/src/components/OutputsTable/OutputCell/OutputCell.tsx index c9f9f93..63b8adf 100644 --- a/src/components/OutputsTable/OutputCell/OutputCell.tsx +++ b/src/components/OutputsTable/OutputCell/OutputCell.tsx @@ -1,17 +1,17 @@ import { api } from "~/utils/api"; import { type PromptVariant, type Scenario } from "../types"; -import { Text, VStack } from "@chakra-ui/react"; +import { type StackProps, Text, VStack } from "@chakra-ui/react"; import { useExperiment, useHandledAsyncCallback } from "~/utils/hooks"; import SyntaxHighlighter from "react-syntax-highlighter"; import { docco } from "react-syntax-highlighter/dist/cjs/styles/hljs"; import stringify from "json-stringify-pretty-compact"; -import { type ReactElement, useState, useEffect, Fragment } from "react"; +import { type ReactElement, useState, useEffect, Fragment, useCallback } from "react"; import useSocket from "~/utils/useSocket"; import { OutputStats } from "./OutputStats"; import { RetryCountdown } from "./RetryCountdown"; import frontendModelProviders from "~/modelProviders/frontendModelProviders"; import { ResponseLog } from "./ResponseLog"; -import { CellContent } from "./CellContent"; +import { CellOptions } from "./TopActions"; const WAITING_MESSAGE_INTERVAL = 20000; @@ -72,37 +72,49 @@ export default function OutputCell({ // TODO: disconnect from socket if we're not streaming anymore const streamedMessage = useSocket(cell?.id); + const mostRecentResponse = cell?.modelResponses[cell.modelResponses.length - 1]; + + const CellWrapper = useCallback( + ({ children, ...props }: StackProps) => ( + + {cell && ( + + )} + + {children} + + {mostRecentResponse && ( + + )} + + ), + [hardRefetching, hardRefetch, mostRecentResponse, scenario], + ); + if (!vars) return null; if (!cell && !fetchingOutput) return ( - + Error retrieving output - + ); if (cell && cell.errorMessage) { return ( - + {cell.errorMessage} - + ); } if (disabledReason) return {disabledReason}; - const mostRecentResponse = cell?.modelResponses[cell.modelResponses.length - 1]; const showLogs = !streamedMessage && !mostRecentResponse?.output; if (showLogs) return ( - + {cell?.jobQueuedAt && } {cell?.jobStartedAt && } {cell?.modelResponses?.map((response) => { @@ -124,9 +136,11 @@ export default function OutputCell({ Array.from({ length: numWaitingMessages }, (_, i) => ( @@ -146,7 +160,7 @@ export default function OutputCell({ {mostRecentResponse?.retryTime && ( )} - + ); const normalizedOutput = mostRecentResponse?.output @@ -157,50 +171,27 @@ export default function OutputCell({ if (mostRecentResponse?.output && normalizedOutput?.type === "json") { return ( - - + - - {stringify(normalizedOutput.value, { maxLength: 40 })} - - - - + {stringify(normalizedOutput.value, { maxLength: 40 })} + + ); } const contentToDisplay = (normalizedOutput?.type === "text" && normalizedOutput.value) || ""; return ( - - - - {contentToDisplay} - - - {mostRecentResponse?.output && ( - - )} - + + {contentToDisplay} + ); } diff --git a/src/components/OutputsTable/OutputCell/PromptModal.tsx b/src/components/OutputsTable/OutputCell/PromptModal.tsx new file mode 100644 index 0000000..18beb61 --- /dev/null +++ b/src/components/OutputsTable/OutputCell/PromptModal.tsx @@ -0,0 +1,36 @@ +import { + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalHeader, + ModalOverlay, + type UseDisclosureReturn, +} from "@chakra-ui/react"; +import { type RouterOutputs } from "~/utils/api"; +import { JSONTree } from "react-json-tree"; + +export default function ExpandedModal(props: { + cell: NonNullable; + disclosure: UseDisclosureReturn; +}) { + return ( + + + + Prompt + + + true} + getItemString={() => ""} + hideRoot + /> + + + + ); +} diff --git a/src/components/OutputsTable/OutputCell/TopActions.tsx b/src/components/OutputsTable/OutputCell/TopActions.tsx new file mode 100644 index 0000000..b018e6c --- /dev/null +++ b/src/components/OutputsTable/OutputCell/TopActions.tsx @@ -0,0 +1,53 @@ +import { HStack, Icon, IconButton, Spinner, Tooltip, useDisclosure } from "@chakra-ui/react"; +import { BsArrowClockwise, BsInfoCircle } from "react-icons/bs"; +import { useExperimentAccess } from "~/utils/hooks"; +import ExpandedModal from "./PromptModal"; +import { type RouterOutputs } from "~/utils/api"; + +export const CellOptions = ({ + cell, + refetchingOutput, + refetchOutput, +}: { + cell: RouterOutputs["scenarioVariantCells"]["get"]; + refetchingOutput: boolean; + refetchOutput: () => void; +}) => { + const { canModify } = useExperimentAccess(); + + const modalDisclosure = useDisclosure(); + + return ( + + {cell && ( + <> + + } + onClick={modalDisclosure.onOpen} + size="xs" + colorScheme="gray" + color="gray.500" + variant="ghost" + /> + + + + )} + {canModify && ( + + } + /> + + )} + + ); +}; diff --git a/src/components/OutputsTable/ScenarioEditor.tsx b/src/components/OutputsTable/ScenarioEditor.tsx index 9f4bf88..5329118 100644 --- a/src/components/OutputsTable/ScenarioEditor.tsx +++ b/src/components/OutputsTable/ScenarioEditor.tsx @@ -1,9 +1,8 @@ -import { useEffect, type DragEvent } from "react"; -import { api } from "~/utils/api"; import { isEqual } from "lodash-es"; -import { type Scenario } from "./types"; +import { useEffect, useState, type DragEvent } from "react"; +import { api } from "~/utils/api"; import { useExperiment, useExperimentAccess, useHandledAsyncCallback } from "~/utils/hooks"; -import { useState } from "react"; +import { type Scenario } from "./types"; import { Box, @@ -12,14 +11,12 @@ import { Icon, IconButton, Spinner, - Stack, + Text, Tooltip, VStack, - Text, } from "@chakra-ui/react"; -import { cellPadding } from "../constants"; import { BsArrowsAngleExpand, BsX } from "react-icons/bs"; -import { RiDraggable } from "react-icons/ri"; +import { cellPadding } from "../constants"; import { FloatingLabelInput } from "./FloatingLabelInput"; import { ScenarioEditorModal } from "./ScenarioEditorModal"; @@ -115,60 +112,44 @@ export default function ScenarioEditor({ onDrop={onReorder} backgroundColor={isDragTarget ? "gray.100" : "transparent"} > - {canModify && props.canHide && ( - - - {/* for some reason the tooltip can't position itself properly relative to the icon without the wrapping box */} - - - - - )} - {variableLabels.length === 0 ? ( {vars.data ? "No scenario variables configured" : "Loading..."} ) : ( - - Scenario - } - onClick={() => setScenarioEditorModalOpen(true)} - boxSize={6} - borderRadius={4} - p={1.5} - minW={0} - colorScheme="gray" - color="gray.500" - variant="ghost" - /> + + Scenario + + } + onClick={() => setScenarioEditorModalOpen(true)} + size="xs" + colorScheme="gray" + color="gray.500" + variant="ghost" + /> + + {canModify && props.canHide && ( + + + } + onClick={onHide} + size="xs" + display="flex" + colorScheme="gray" + color="gray.500" + variant="ghost" + /> + + )} {variableLabels.map((key) => { const value = values[key] ?? ""; diff --git a/src/components/OutputsTable/ScenarioEditorModal.tsx b/src/components/OutputsTable/ScenarioEditorModal.tsx index dc8cfcb..dec1bd7 100644 --- a/src/components/OutputsTable/ScenarioEditorModal.tsx +++ b/src/components/OutputsTable/ScenarioEditorModal.tsx @@ -1,7 +1,6 @@ import { Button, HStack, - Icon, Modal, ModalBody, ModalCloseButton, @@ -14,7 +13,6 @@ import { VStack, } from "@chakra-ui/react"; import { useEffect, useState } from "react"; -import { BsFileTextFill } from "react-icons/bs"; import { isEqual } from "lodash-es"; import { api } from "~/utils/api"; @@ -60,8 +58,6 @@ export const ScenarioEditorModal = ({ await utils.scenarios.list.invalidate(); }, [mutation, values]); - console.log("scenario", scenario); - const vars = api.templateVars.list.useQuery({ experimentId: experiment.data?.id ?? "" }); const variableLabels = vars.data?.map((v) => v.label) ?? []; @@ -73,12 +69,7 @@ export const ScenarioEditorModal = ({ > - - - - Scenario - - + diff --git a/src/components/OutputsTable/ScenarioRow.tsx b/src/components/OutputsTable/ScenarioRow.tsx index d9544ce..41b4fcf 100644 --- a/src/components/OutputsTable/ScenarioRow.tsx +++ b/src/components/OutputsTable/ScenarioRow.tsx @@ -1,6 +1,5 @@ -import { Box, GridItem } from "@chakra-ui/react"; +import { GridItem } from "@chakra-ui/react"; import React, { useState } from "react"; -import { cellPadding } from "../constants"; import OutputCell from "./OutputCell/OutputCell"; import ScenarioEditor from "./ScenarioEditor"; import type { PromptVariant, Scenario } from "./types"; @@ -39,9 +38,7 @@ const ScenarioRow = (props: { colStart={i + 2} {...borders} > - - - + ))} diff --git a/src/modelProviders/openai-ChatCompletion/getCompletion.ts b/src/modelProviders/openai-ChatCompletion/getCompletion.ts index 79ec75b..462f2fa 100644 --- a/src/modelProviders/openai-ChatCompletion/getCompletion.ts +++ b/src/modelProviders/openai-ChatCompletion/getCompletion.ts @@ -6,7 +6,7 @@ import { } from "openai/resources/chat"; import { countOpenAIChatTokens } from "~/utils/countTokens"; import { type CompletionResponse } from "../types"; -import { omit } from "lodash-es"; +import { isArray, isString, omit } from "lodash-es"; import { openai } from "~/server/utils/openai"; import { truthyFilter } from "~/utils/utils"; import { APIError } from "openai"; @@ -40,6 +40,8 @@ const mergeStreamedChunks = ( ((choice.delta.function_call.arguments as string) ?? ""); } } else { + // @ts-expect-error the types are correctly telling us that finish_reason + // could be null, but don't want to fix it right now. choices.push({ ...omit(choice, "delta"), message: { role: "assistant", ...choice.delta } }); } } @@ -64,6 +66,7 @@ export async function getCompletion( try { if (onStream) { + console.log("got started"); const resp = await openai.chat.completions.create( { ...input, stream: true }, { @@ -71,9 +74,11 @@ export async function getCompletion( }, ); for await (const part of resp) { + console.log("got part", part); finalCompletion = mergeStreamedChunks(finalCompletion, part); onStream(finalCompletion); } + console.log("got final", finalCompletion); if (!finalCompletion) { return { type: "error", @@ -121,9 +126,17 @@ export async function getCompletion( }; } catch (error: unknown) { if (error instanceof APIError) { + // The types from the sdk are wrong + const rawMessage = error.message as string | string[]; + // If the message is not a string, stringify it + const message = isString(rawMessage) + ? rawMessage + : isArray(rawMessage) + ? rawMessage.map((m) => m.toString()).join("\n") + : (rawMessage as any).toString(); return { type: "error", - message: error.message, + message, autoRetry: error.status === 429 || error.status === 503, statusCode: error.status, }; diff --git a/src/pages/api/experiments/og-image.tsx b/src/pages/api/experiments/og-image.tsx index 5246dcd..55f7687 100644 --- a/src/pages/api/experiments/og-image.tsx +++ b/src/pages/api/experiments/og-image.tsx @@ -9,7 +9,7 @@ const inconsolataRegularFontP = fetch( new URL("../../../../public/fonts/Inconsolata_SemiExpanded-Medium.ttf", import.meta.url), ).then((res) => res.arrayBuffer()); -const OgImage = async (req: NextApiRequest, res: NextApiResponse) => { +const OgImage = async (req: NextApiRequest, _res: NextApiResponse) => { // @ts-expect-error - nextUrl is not defined on NextApiRequest for some reason const searchParams = req.nextUrl?.searchParams as URLSearchParams; const experimentLabel = searchParams.get("experimentLabel"); diff --git a/src/pages/world-champs/signup.tsx b/src/pages/world-champs/signup.tsx index cc01888..5a94ee3 100644 --- a/src/pages/world-champs/signup.tsx +++ b/src/pages/world-champs/signup.tsx @@ -44,7 +44,7 @@ const TopNavbar = () => ( // Shows how long until the competition starts. Refreshes every second function CountdownTimer(props: { date: Date } & TextProps) { - const [now, setNow] = useState(dayjs(0)); + const [now, setNow] = useState(dayjs()); useInterval(() => { setNow(dayjs()); @@ -52,7 +52,7 @@ function CountdownTimer(props: { date: Date } & TextProps) { const { date, ...rest } = props; - const kickoff = dayjs(props.date); + const kickoff = dayjs(date); const diff = kickoff.diff(now, "second"); const days = Math.floor(diff / 86400); const hours = Math.floor((diff % 86400) / 3600); @@ -60,7 +60,7 @@ function CountdownTimer(props: { date: Date } & TextProps) { const seconds = Math.floor(diff % 60); return ( - + Kickoff in {" "} diff --git a/src/server/api/routers/worldChamps.router.ts b/src/server/api/routers/worldChamps.router.ts index bd760a3..72e11cd 100644 --- a/src/server/api/routers/worldChamps.router.ts +++ b/src/server/api/routers/worldChamps.router.ts @@ -3,7 +3,7 @@ import { prisma } from "~/server/db"; import { requireNothing } from "~/utils/accessControl"; export const worldChampsRouter = createTRPCRouter({ - userStatus: publicProcedure.query(async ({ input, ctx }) => { + userStatus: publicProcedure.query(async ({ ctx }) => { const userId = ctx.session?.user.id; if (!userId) { diff --git a/src/server/utils/deriveNewContructFn.ts b/src/server/utils/deriveNewContructFn.ts index 32b7696..898a22d 100644 --- a/src/server/utils/deriveNewContructFn.ts +++ b/src/server/utils/deriveNewContructFn.ts @@ -3,7 +3,7 @@ import ivm from "isolated-vm"; import dedent from "dedent"; import { openai } from "./openai"; import { isObject } from "lodash-es"; -import { type CompletionCreateParams } from "openai/resources/chat/completions"; +import type { CreateChatCompletionRequestMessage } from "openai/resources/chat/completions"; import formatPromptConstructor from "~/utils/formatPromptConstructor"; import { type SupportedProvider, type Model } from "~/modelProviders/types"; import modelProviders from "~/modelProviders/modelProviders"; @@ -44,7 +44,7 @@ const requestUpdatedPromptFunction = async ( let newContructionFn = ""; for (let i = 0; i < NUM_RETRIES; i++) { try { - const messages: CompletionCreateParams.CreateChatCompletionRequestNonStreaming.Message[] = [ + const messages: CreateChatCompletionRequestMessage[] = [ { role: "system", content: `Your job is to update prompt constructor functions. Here is the api shape for the current model:\n---\n${JSON.stringify( diff --git a/src/theme/ChakraThemeProvider.tsx b/src/theme/ChakraThemeProvider.tsx index 94d3a6c..0c3f247 100644 --- a/src/theme/ChakraThemeProvider.tsx +++ b/src/theme/ChakraThemeProvider.tsx @@ -1,10 +1,23 @@ import { extendTheme } from "@chakra-ui/react"; import "@fontsource/inconsolata"; import { ChakraProvider } from "@chakra-ui/react"; +import { modalAnatomy } from "@chakra-ui/anatomy"; +import { createMultiStyleConfigHelpers } from "@chakra-ui/styled-system"; const systemFont = 'ui-sans-serif, -apple-system, "system-ui", "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"'; +/* eslint-disable @typescript-eslint/unbound-method */ +const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpers( + modalAnatomy.keys, +); + +const modalTheme = defineMultiStyleConfig({ + baseStyle: definePartsStyle({ + dialog: { borderRadius: "sm" }, + }), +}); + const theme = extendTheme({ styles: { global: (props: { colorMode: "dark" | "light" }) => ({ @@ -39,6 +52,7 @@ const theme = extendTheme({ }, }, }, + Modal: modalTheme, }, });