Migrate to scoped nanoid()

This commit is contained in:
Enrico Ros
2024-06-16 17:33:46 -07:00
parent b31c891772
commit e4bd5f865c
21 changed files with 104 additions and 89 deletions
-20
View File
@@ -57,7 +57,6 @@
"tesseract.js": "^5.1.0",
"tiktoken": "^1.0.15",
"turndown": "^7.2.0",
"uuid": "^9.0.1",
"zod": "^3.23.8",
"zustand": "^4.5.2"
},
@@ -74,7 +73,6 @@
"@types/react-katex": "^3.0.4",
"@types/react-timeago": "^4.1.7",
"@types/turndown": "^5.0.4",
"@types/uuid": "^9.0.8",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.3",
"prettier": "^3.3.1",
@@ -2110,12 +2108,6 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz",
"integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ=="
},
"node_modules/@types/uuid": {
"version": "9.0.8",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
"dev": true
},
"node_modules/@typescript-eslint/parser": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz",
@@ -8801,18 +8793,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vfile": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz",
-2
View File
@@ -66,7 +66,6 @@
"tesseract.js": "^5.1.0",
"tiktoken": "^1.0.15",
"turndown": "^7.2.0",
"uuid": "^9.0.1",
"zod": "^3.23.8",
"zustand": "^4.5.2"
},
@@ -83,7 +82,6 @@
"@types/react-katex": "^3.0.4",
"@types/react-timeago": "^4.1.7",
"@types/turndown": "^5.0.4",
"@types/uuid": "^9.0.8",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.3",
"prettier": "^3.3.1",
@@ -2,9 +2,9 @@ import * as React from 'react';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { useShallow } from 'zustand/react/shallow';
import { v4 as uuidv4 } from 'uuid';
import { DConversationId } from '~/common/stores/chat/chat.conversation';
import { agiUuid } from '~/common/util/idUtils';
import { useChatStore } from '~/common/stores/chat/store-chats';
@@ -55,7 +55,7 @@ interface AppChatPanesStore extends AppChatPanesState {
function createPane(conversationId: DConversationId | null = null): ChatPane {
return {
paneId: uuidv4(),
paneId: agiUuid('chat-pane'),
conversationId,
history: conversationId ? [conversationId] : [],
historyIndex: conversationId ? 0 : -1,
@@ -64,7 +64,7 @@ function createPane(conversationId: DConversationId | null = null): ChatPane {
function duplicatePane(pane: ChatPane): ChatPane {
return {
paneId: uuidv4(),
paneId: agiUuid('chat-pane'),
conversationId: pane.conversationId,
history: [...pane.history],
historyIndex: pane.historyIndex,
+2 -2
View File
@@ -1,5 +1,4 @@
import * as React from 'react';
import { nanoid } from 'nanoid';
import type { SxProps } from '@mui/joy/styles/types';
import { Box, Button, ButtonGroup, Dropdown, FormControl, Grid, IconButton, Menu, MenuButton, MenuItem, Textarea, Typography } from '@mui/joy';
@@ -15,6 +14,7 @@ import StopOutlinedIcon from '@mui/icons-material/StopOutlined';
import { imaginePromptFromText } from '~/modules/aifn/imagine/imaginePromptFromText';
import { agiUuid } from '~/common/util/idUtils';
import { animationEnterBelow } from '~/common/util/animUtils';
import { lineHeightTextareaMd } from '~/common/app.theme';
import { useUIPreferencesStore } from '~/common/state/store-ui';
@@ -81,7 +81,7 @@ export function PromptComposer(props: {
clearCurrentIdea();
if (nonEmptyPrompt?.trim()) {
onPromptEnqueue([{
dpId: nanoid(),
dpId: agiUuid('draw-prompt'),
prompt: nonEmptyPrompt,
_repeatCount: isRepeatShown ? tempRepeat : 1,
}]);
+2 -2
View File
@@ -1,5 +1,4 @@
import * as React from 'react';
import { v4 as uuidv4 } from 'uuid';
import { Alert, Box, Button, Card, CardContent, CircularProgress, Divider, FormLabel, Grid, IconButton, LinearProgress, Tab, tabClasses, TabList, TabPanel, Tabs, Typography } from '@mui/joy';
import AddIcon from '@mui/icons-material/Add';
@@ -10,6 +9,7 @@ import { LLMChainStep, useLLMChain } from '~/modules/aifn/useLLMChain';
import { RenderMarkdownMemo } from '~/modules/blocks/markdown/RenderMarkdown';
import { GoodTooltip } from '~/common/components/GoodTooltip';
import { agiUuid } from '~/common/util/idUtils';
import { copyToClipboard } from '~/common/util/clipboardUtils';
import { useFormEditTextArray } from '~/common/components/forms/useFormEditTextArray';
import { useLLMSelect, useLLMSelectLocalState } from '~/common/components/forms/useLLMSelect';
@@ -106,7 +106,7 @@ export function Creator(props: { display: boolean }) {
const { steps: creationChainSteps, id: chainId } = React.useMemo(() => {
return {
steps: createChain(editedInstructions, PromptTitles),
id: uuidv4(),
id: agiUuid('persona-creator-chain'),
};
}, [editedInstructions]);
+7 -6
View File
@@ -1,8 +1,9 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { shallow } from 'zustand/shallow';
import { createBase64UuidV4 } from '~/common/util/textUtils';
import { agiUuid } from '~/common/util/idUtils';
import { useShallow } from 'zustand/react/shallow';
// constraint the max number of saved prompts, to stay below localStorage quota
const MAX_SAVED_PROMPTS = 100;
@@ -60,7 +61,7 @@ const useAppPersonasStore = create<AppPersonasStore>()(persist(
prependSimplePersona: (systemPrompt: string, inputText: string, inputProvenance?: SimplePersonaProvenance, llmLabel?: string) =>
_set(state => {
const newPersona: SimplePersona = {
id: createBase64UuidV4(),
id: agiUuid('persona-simple'),
systemPrompt,
creationDate: new Date().toISOString(),
inputProvenance,
@@ -94,14 +95,14 @@ const useAppPersonasStore = create<AppPersonasStore>()(persist(
));
export function useSimplePersonas() {
const simplePersonas = useAppPersonasStore(state => state.simplePersonas, shallow);
const simplePersonas = useAppPersonasStore(useShallow(state => state.simplePersonas));
return { simplePersonas };
}
export function useSimplePersona(simplePersonaId: string) {
const simplePersona = useAppPersonasStore(state => {
const simplePersona = useAppPersonasStore(useShallow(state => {
return state.simplePersonas.find(persona => persona.id === simplePersonaId) ?? null;
}, shallow);
}));
return { simplePersona };
}
@@ -1,6 +1,6 @@
import { callBrowseFetchPage } from '~/modules/browse/browse.client';
import { createBase64UuidV4 } from '~/common/util/textUtils';
import { agiUuid } from '~/common/util/idUtils';
import { htmlTableToMarkdown } from '~/common/util/htmlTableToMarkdown';
import { pdfToImageDataURLs, pdfToText } from '~/common/util/pdfUtils';
@@ -93,7 +93,7 @@ const IMAGE_MIMETYPES: string[] = [
*/
export function attachmentCreate(source: AttachmentDraftSource): AttachmentDraft {
return {
id: createBase64UuidV4(),
id: agiUuid('attachment-draft'),
source: source,
label: 'Loading...',
ref: '',
+2 -2
View File
@@ -1,6 +1,6 @@
import * as React from 'react';
import { v4 as uuidv4 } from 'uuid';
import { agiUuid } from '~/common/util/idUtils';
import { customEventHelpers } from '~/common/util/eventUtils';
import type { ConversationHandler } from './ConversationHandler';
@@ -18,7 +18,7 @@ export interface DEphemeral {
function createDEphemeral(title: string, initialText: string): DEphemeral {
return {
id: uuidv4(),
id: agiUuid('chat-ephemerals-item'),
title: title,
text: initialText,
state: {},
+3 -2
View File
@@ -1,8 +1,9 @@
import { create } from 'zustand';
import { v4 as uuidv4 } from 'uuid';
import type { SnackbarTypeMap } from '@mui/joy';
import { agiUuid } from '~/common/util/idUtils';
export const SNACKBAR_ANIMATION_DURATION = 200;
@@ -42,7 +43,7 @@ export const useSnackbarsStore = create<SnackbarStore>()(
let { key, ...rest } = snackbar;
// unique key
key += '-' + uuidv4();
key += '-' + agiUuid('snackbar-item');
// append the snackbar
const newSnackbar = { key, ...rest };
+4 -2
View File
@@ -1,5 +1,7 @@
import * as React from 'react';
import { nanoid } from 'nanoid';
import { agiUuid } from '~/common/util/idUtils';
/**
* Pure async function that operates on an item, can monitor the abort signal, and return or throw
@@ -28,7 +30,7 @@ export class ProcessingQueue<TItem> extends EventTarget {
// returns a promise that resolves after processing
enqueueItem(item: TItem, priority: number = 0): Promise<TItem> {
const taskId = nanoid();
const taskId = agiUuid('processing-queue-task');
const enqueuedAt = Date.now();
// Create a new AbortController for each task
+2 -2
View File
@@ -1,8 +1,8 @@
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { v4 as uuidv4 } from 'uuid';
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
import { agiUuid } from '~/common/util/idUtils';
export interface DFolder {
@@ -51,7 +51,7 @@ export const useFolderStore = create<FolderStore>()(devtools(
createFolder: (title: string, color?: string) => {
const newFolder: DFolder = {
id: uuidv4(),
id: agiUuid('chat-folders-item'),
title,
conversationIds: [],
color,
+3 -4
View File
@@ -1,8 +1,7 @@
import { v4 as uuidv4 } from 'uuid';
import { defaultSystemPurposeId, SystemPurposeId } from '../../../data';
import { DMessage, DMessageId, duplicateDMessage } from './chat.message';
import { agiUuid } from '~/common/util/idUtils';
/// Conversation
@@ -45,7 +44,7 @@ export type DConversationId = string;
export function createDConversation(systemPurposeId?: SystemPurposeId): DConversation {
return {
id: uuidv4(),
id: agiUuid('chat-dconversation'),
messages: [],
@@ -80,7 +79,7 @@ export function duplicateCConversation(conversation: DConversation, lastMessageI
const newTitle = getNextBranchTitle(conversationTitle(conversation));
return {
id: uuidv4(),
id: agiUuid('chat-dconversation'),
messages: conversation.messages
.slice(0, messagesToKeep)
+3 -3
View File
@@ -1,6 +1,6 @@
import type { DBlobAssetId } from '~/modules/dblobs/dblobs.types';
import { createBase64UuidV4 } from '~/common/util/textUtils';
import { agiUuid } from '~/common/util/idUtils';
// Message
@@ -117,7 +117,7 @@ export function createTextContentDMessage(role: DMessageRole, text: string): DMe
export function createDMessage(role: DMessageRole, fragments: DMessageFragment[]): DMessage {
return {
id: createBase64UuidV4(),
id: agiUuid('chat-dmessage'),
role: role,
fragments,
@@ -213,7 +213,7 @@ export function createDMessageDataRefDBlob(dblobAssetId: DBlobAssetId, mimeType:
export function duplicateDMessage(message: Readonly<DMessage>): DMessage {
return {
id: createBase64UuidV4(),
id: agiUuid('chat-dmessage'),
role: message.role,
fragments: duplicateDMessageFragments(message.fragments),
+2 -2
View File
@@ -1,13 +1,13 @@
import { create } from 'zustand';
import { createJSONStorage, devtools, persist } from 'zustand/middleware';
import { useShallow } from 'zustand/react/shallow';
import { v4 as uuidv4 } from 'uuid';
import type { SystemPurposeId } from '../../../data';
import { DLLMId, findLLMOrThrow, getChatLLMId } from '~/modules/llms/store-llms';
import { convertDConversation_V3_V4 } from '~/modules/trade/trade.types';
import { agiUuid } from '~/common/util/idUtils';
import { backupIdbV3, idbStateStorage } from '~/common/util/idbUtils';
import type { DMessage, DMessageFragment, DMessageId, DMessageMetadata } from './chat.message';
@@ -76,7 +76,7 @@ export const useChatStore = create<ConversationsStore>()(devtools(
if (existing) {
existing?.abortController?.abort();
if (preventClash) {
conversation.id = uuidv4();
conversation.id = agiUuid('chat-dconversation');
console.warn('Conversation ID clash, changing ID to', conversation.id);
}
}
+55
View File
@@ -0,0 +1,55 @@
import { nanoid } from 'nanoid';
// This is here to index all the UUIDs in the application
type UidScope =
| 'attachment-draft'
| 'beam-fusion'
| 'beam-preset-config'
| 'beam-ray'
| 'chat-dconversation'
| 'chat-dmessage'
| 'chat-ephemerals-item'
| 'chat-folders-item'
| 'chat-pane'
| 'dblob-asset'
| 'draw-prompt'
| 'persona-creator-chain'
| 'persona-simple'
| 'processing-queue-task'
| 'server-storage-deletion-key'
| 'server-storage-owner'
| 'snackbar-item'
;
/**
* Application-wide unique identifier generator
* @param _scope Does not influcence the ID generation, but is used to index all the IDs in the application
*/
export function agiUuid(_scope: UidScope) {
return nanoid();
}
/*
import { v4 as uuidv4 } from 'uuid';
export function createBase64UuidV4(): string {
return uuidToBase64(uuidv4());
}
function uuidToBase64(uuid: string): string {
// Remove hyphens from the UUID
const cleanUuid = uuid.replaceAll('-', '');
// Convert the cleaned UUID to a byte array
const uuidBytes = new Uint8Array(16);
for (let i = 0; i < 32; i += 2)
uuidBytes[i / 2] = parseInt(cleanUuid.substring(i, i + 2), 16);
// Convert byte array to a Base64 string
const base64 = btoa(String.fromCharCode.apply(null, uuidBytes as any));
// Remove '=' end padding
return base64.replace(/=+$/, '');
}
*/
-24
View File
@@ -1,6 +1,3 @@
import { v4 as uuidv4 } from 'uuid';
export function capitalizeFirstLetter(string: string) {
return string?.length ? (string.charAt(0).toUpperCase() + string.slice(1)) : string;
}
@@ -18,24 +15,3 @@ export function ellipsizeMiddle(text: string, maxLength: number) {
const half = Math.floor(maxLength / 2);
return text.slice(0, half) + '…' + text.slice(-(maxLength - half - 1));
}
export function createBase64UuidV4(): string {
return uuidToBase64(uuidv4());
}
function uuidToBase64(uuid: string): string {
// Remove hyphens from the UUID
const cleanUuid = uuid.replaceAll('-', '');
// Convert the cleaned UUID to a byte array
const uuidBytes = new Uint8Array(16);
for (let i = 0; i < 32; i += 2)
uuidBytes[i / 2] = parseInt(cleanUuid.substring(i, i + 2), 16);
// Convert byte array to a Base64 string
const base64 = btoa(String.fromCharCode.apply(null, uuidBytes as any));
// Remove '=' end padding
return base64.replace(/=+$/, '');
}
+2 -2
View File
@@ -1,10 +1,10 @@
import * as React from 'react';
import { v4 as uuidv4 } from 'uuid';
import type { StateCreator } from 'zustand/vanilla';
import type { DLLMId } from '~/modules/llms/store-llms';
import type { DMessage } from '~/common/stores/chat/chat.message';
import { agiUuid } from '~/common/util/idUtils';
import { CUSTOM_FACTORY_ID, FFactoryId, findFusionFactory, FUSION_FACTORIES, FUSION_FACTORY_DEFAULT } from './instructions/beam.gather.factories';
import { RootStoreSlice } from '../store-beam-vanilla';
@@ -47,7 +47,7 @@ export interface BFusion {
const createBFusion = (factoryId: FFactoryId, instructions: Instruction[], llmId: DLLMId | null): BFusion => ({
// const
fusionId: uuidv4(),
fusionId: agiUuid('beam-fusion'),
factoryId,
// options
+2 -2
View File
@@ -1,4 +1,3 @@
import { v4 as uuidv4 } from 'uuid';
import type { StateCreator } from 'zustand/vanilla';
import { streamAssistantMessage } from '../../../apps/chat/editors/chat-stream';
@@ -6,6 +5,7 @@ import { streamAssistantMessage } from '../../../apps/chat/editors/chat-stream';
import type { DLLMId } from '~/modules/llms/store-llms';
import type { VChatMessageIn } from '~/modules/llms/llm.client';
import { agiUuid } from '~/common/util/idUtils';
import { createEmptyDMessage, DMessage, duplicateDMessage, messageSingleTextOrThrow, pendDMessage } from '~/common/stores/chat/chat.message';
import { getUXLabsHighPerformance } from '~/common/state/store-ux-labs';
@@ -30,7 +30,7 @@ export interface BRay {
export function createBRayEmpty(llmId: DLLMId | null): BRay {
return {
rayId: uuidv4(),
rayId: agiUuid('beam-ray'),
status: 'empty',
message: createEmptyDMessage('assistant'), // [state] assistant:Ray_empty
rayLlmId: llmId,
+4 -2
View File
@@ -1,8 +1,10 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { v4 as uuidv4 } from 'uuid';
import type { DLLMId } from '~/modules/llms/store-llms';
import { agiUuid } from '~/common/util/idUtils';
import type { FFactoryId } from './gather/instructions/beam.gather.factories';
@@ -60,7 +62,7 @@ export const useModuleBeamStore = create<ModuleBeamStore>()(persist(
addPreset: (name, rayLlmIds, gatherLlmId, gatherFactoryId) => _set(state => ({
presets: [...state.presets, {
id: uuidv4(),
id: agiUuid('beam-preset-config'),
name,
rayLlmIds,
gatherLlmId: gatherLlmId ?? undefined,
+2 -2
View File
@@ -1,4 +1,4 @@
import { nanoid } from 'nanoid';
import { agiUuid } from '~/common/util/idUtils';
// DB - Assets
@@ -194,7 +194,7 @@ export function _createAssetObject<TType extends DBlobAssetType, TMime extends D
): DBlobAssetImplV1<TType, TMime, TMeta> {
const creationDate = new Date();
return {
id: nanoid(),
id: agiUuid('dblob-asset'),
assetType,
label,
data,
+4 -3
View File
@@ -1,4 +1,3 @@
import { v4 as uuidv4 } from 'uuid';
import { z } from 'zod';
import { LinkStorageDataType, LinkStorageVisibility } from '@prisma/client';
@@ -6,6 +5,8 @@ import { LinkStorageDataType, LinkStorageVisibility } from '@prisma/client';
import { prismaDb } from '~/server/prisma/prismaDb';
import { publicProcedure } from '~/server/api/trpc.server';
import { agiUuid } from '~/common/util/idUtils';
// configuration
const DEFAULT_EXPIRES_SECONDS = 60 * 60 * 24 * 30; // 30 days
@@ -112,7 +113,7 @@ export const storagePutProcedure =
deletionKey: true,
},
data: {
ownerId: ownerId || uuidv4(),
ownerId: ownerId || agiUuid('server-storage-owner'),
visibility: LinkStorageVisibility.UNLISTED,
dataType,
dataTitle,
@@ -121,7 +122,7 @@ export const storagePutProcedure =
expiresAt: expiresSeconds === 0
? undefined // never expires
: new Date(Date.now() + 1000 * (expiresSeconds || DEFAULT_EXPIRES_SECONDS)), // default
deletionKey: uuidv4(),
deletionKey: agiUuid('server-storage-deletion-key'),
isDeleted: false,
},
});