diff --git a/CLAUDE.md b/CLAUDE.md index 5c942b83d4..baa91b4834 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -120,7 +120,7 @@ UI Library: `@packages/ui` - **JSON Fields**: For JSON support, add `{ mode: 'json' }`, refer to `preference.ts` table definition - **JSON Serialization**: For JSON fields, no need to manually serialize/deserialize when reading/writing to database, Drizzle handles this automatically - **Timestamps**: Use existing `crudTimestamps` utility -- **Migrations**: Generate via `yarn run migrations:generate` +- **Migrations**: Generate via `yarn run db:migrations:generate` ## Data Access Patterns diff --git a/migrations/README.md b/migrations/README.md index fc11adc188..5ade119ec8 100644 --- a/migrations/README.md +++ b/migrations/README.md @@ -1,6 +1,10 @@ **THIS DIRECTORY IS NOT FOR RUNTIME USE** +**v2 Data Refactoring Notice** +Before the official release of the alpha version, the database structure may change at any time. To maintain simplicity, the database migration files will be periodically reinitialized, which may cause the application to fail. If this occurs, please delete the `cherrystudio.sqlite` file located in the user data directory. + - Using `libsql` as the `sqlite3` driver, and `drizzle` as the ORM and database migration tool +- Table schemas are defined in `src\main\data\db\schemas` - `migrations/sqlite-drizzle` contains auto-generated migration data. Please **DO NOT** modify it. - If table structure changes, we should run migrations. -- To generate migrations, use the command `yarn run migrations:generate` +- To generate migrations, use the command `yarn run db:migrations:generate` diff --git a/migrations/sqlite-drizzle/0001_faulty_ogun.sql b/migrations/sqlite-drizzle/0001_faulty_ogun.sql new file mode 100644 index 0000000000..969e386dcb --- /dev/null +++ b/migrations/sqlite-drizzle/0001_faulty_ogun.sql @@ -0,0 +1,3 @@ +ALTER TABLE `message` ADD `stats` text;--> statement-breakpoint +ALTER TABLE `message` DROP COLUMN `usage`;--> statement-breakpoint +ALTER TABLE `message` DROP COLUMN `metrics`; \ No newline at end of file diff --git a/migrations/sqlite-drizzle/meta/0001_snapshot.json b/migrations/sqlite-drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000000..533c642b04 --- /dev/null +++ b/migrations/sqlite-drizzle/meta/0001_snapshot.json @@ -0,0 +1,655 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "ae53858a-1786-4059-9ff7-9e87267911b6", + "prevId": "62a198e0-bfc2-4db1-af58-7e479fedd7b9", + "tables": { + "app_state": { + "name": "app_state", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "entity_tag": { + "name": "entity_tag", + "columns": { + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tag_id": { + "name": "tag_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "entity_tag_tag_id_idx": { + "name": "entity_tag_tag_id_idx", + "columns": [ + "tag_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "entity_tag_tag_id_tag_id_fk": { + "name": "entity_tag_tag_id_tag_id_fk", + "tableFrom": "entity_tag", + "tableTo": "tag", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "entity_tag_entity_type_entity_id_tag_id_pk": { + "columns": [ + "entity_type", + "entity_id", + "tag_id" + ], + "name": "entity_tag_entity_type_entity_id_tag_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "group_entity_sort_idx": { + "name": "group_entity_sort_idx", + "columns": [ + "entity_type", + "sort_order" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "message": { + "name": "message", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "topic_id": { + "name": "topic_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_group_id": { + "name": "response_group_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "assistant_id": { + "name": "assistant_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "assistant_meta": { + "name": "assistant_meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_meta": { + "name": "model_meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "stats": { + "name": "stats", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "trace_id": { + "name": "trace_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "searchable_text": { + "name": "searchable_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "message_parent_id_idx": { + "name": "message_parent_id_idx", + "columns": [ + "parent_id" + ], + "isUnique": false + }, + "message_topic_created_idx": { + "name": "message_topic_created_idx", + "columns": [ + "topic_id", + "created_at" + ], + "isUnique": false + }, + "message_trace_id_idx": { + "name": "message_trace_id_idx", + "columns": [ + "trace_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "message_topic_id_topic_id_fk": { + "name": "message_topic_id_topic_id_fk", + "tableFrom": "message", + "tableTo": "topic", + "columnsFrom": [ + "topic_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "message_parent_id_message_id_fk": { + "name": "message_parent_id_message_id_fk", + "tableFrom": "message", + "tableTo": "message", + "columnsFrom": [ + "parent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": { + "message_role_check": { + "name": "message_role_check", + "value": "\"message\".\"role\" IN ('user', 'assistant', 'system')" + }, + "message_status_check": { + "name": "message_status_check", + "value": "\"message\".\"status\" IN ('success', 'error', 'paused')" + } + } + }, + "preference": { + "name": "preference", + "columns": { + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "preference_scope_key_pk": { + "columns": [ + "scope", + "key" + ], + "name": "preference_scope_key_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tag": { + "name": "tag", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "tag_name_unique": { + "name": "tag_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "topic": { + "name": "topic", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "assistant_id": { + "name": "assistant_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "assistant_meta": { + "name": "assistant_meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_pinned": { + "name": "is_pinned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "pinned_order": { + "name": "pinned_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "is_name_manually_edited": { + "name": "is_name_manually_edited", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "topic_group_updated_idx": { + "name": "topic_group_updated_idx", + "columns": [ + "group_id", + "updated_at" + ], + "isUnique": false + }, + "topic_group_sort_idx": { + "name": "topic_group_sort_idx", + "columns": [ + "group_id", + "sort_order" + ], + "isUnique": false + }, + "topic_updated_at_idx": { + "name": "topic_updated_at_idx", + "columns": [ + "updated_at" + ], + "isUnique": false + }, + "topic_is_pinned_idx": { + "name": "topic_is_pinned_idx", + "columns": [ + "is_pinned", + "pinned_order" + ], + "isUnique": false + }, + "topic_assistant_id_idx": { + "name": "topic_assistant_id_idx", + "columns": [ + "assistant_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "topic_group_id_group_id_fk": { + "name": "topic_group_id_group_id_fk", + "tableFrom": "topic", + "tableTo": "group", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/migrations/sqlite-drizzle/meta/_journal.json b/migrations/sqlite-drizzle/meta/_journal.json index 781e2d3d99..c42fbfed83 100644 --- a/migrations/sqlite-drizzle/meta/_journal.json +++ b/migrations/sqlite-drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1766588456958, "tag": "0000_init", "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1766670360754, + "tag": "0001_faulty_ogun", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/package.json b/package.json index fe81ff1ebf..d1769d1f1c 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "format:check": "biome format && biome lint", "prepare": "git config blame.ignoreRevsFile .git-blame-ignore-revs && husky", "claude": "dotenv -e .env -- claude", - "migrations:generate": "drizzle-kit generate --config ./migrations/sqlite-drizzle.config.ts", + "db:migrations:generate": "drizzle-kit generate --config ./migrations/sqlite-drizzle.config.ts", "release:aicore:alpha": "yarn workspace @cherrystudio/ai-core version prerelease --preid alpha --immediate && yarn workspace @cherrystudio/ai-core build && yarn workspace @cherrystudio/ai-core npm publish --tag alpha --access public", "release:aicore:beta": "yarn workspace @cherrystudio/ai-core version prerelease --preid beta --immediate && yarn workspace @cherrystudio/ai-core build && yarn workspace @cherrystudio/ai-core npm publish --tag beta --access public", "release:aicore": "yarn workspace @cherrystudio/ai-core version patch --immediate && yarn workspace @cherrystudio/ai-core build && yarn workspace @cherrystudio/ai-core npm publish --access public", diff --git a/packages/shared/data/README.md b/packages/shared/data/README.md index b65af18e33..c522d3138c 100644 --- a/packages/shared/data/README.md +++ b/packages/shared/data/README.md @@ -7,25 +7,31 @@ This directory contains shared type definitions and schemas for the Cherry Studi ``` packages/shared/data/ ├── api/ # Data API type system -│ ├── index.ts # Barrel exports for clean imports -│ ├── apiSchemas.ts # API endpoint definitions and mappings -│ ├── apiTypes.ts # Core request/response infrastructure types -│ ├── apiModels.ts # Business entity types and DTOs -│ ├── apiPaths.ts # API path definitions and utilities -│ └── errorCodes.ts # Standardized error handling +│ ├── index.ts # Barrel exports for clean imports +│ ├── apiSchemas.ts # API endpoint definitions and mappings +│ ├── apiTypes.ts # Core request/response infrastructure types +│ ├── apiModels.ts # Business entity types and DTOs +│ ├── apiPaths.ts # API path definitions and utilities +│ └── errorCodes.ts # Standardized error handling ├── cache/ # Cache system type definitions -│ ├── cacheTypes.ts # Core cache infrastructure types -│ ├── cacheSchemas.ts # Cache key schemas and type mappings -│ └── cacheValueTypes.ts # Cache value type definitions +│ ├── cacheTypes.ts # Core cache infrastructure types +│ ├── cacheSchemas.ts # Cache key schemas and type mappings +│ └── cacheValueTypes.ts # Cache value type definitions ├── preference/ # Preference system type definitions -│ ├── preferenceTypes.ts # Core preference system types +│ ├── preferenceTypes.ts # Core preference system types │ └── preferenceSchemas.ts # Preference schemas and default values -└── README.md # This file +├── types/ # Shared data types for Main/Renderer +└── README.md # This file ``` ## 🏗️ System Overview -This directory provides type definitions for three main data management systems: +This directory provides type definitions for four main data management systems: + +### Types System (`types/`) +- **Purpose**: Shared data types for cross-process (Main/Renderer) communication and database schemas +- **Features**: Database table field types, business entity definitions +- **Usage**: Used in Drizzle ORM schemas via `.$type()` and runtime type checking ### API System (`api/`) - **Purpose**: Type-safe IPC communication between Main and Renderer processes @@ -72,6 +78,11 @@ import type { PreferenceKeyType, PreferenceDefaultScopeType } from '@shared/data ## 🔧 Development Guidelines +### Adding Shared Types +1. Create or update type file in `types/` directory +2. Use camelCase for field names +3. Reference types in Drizzle schemas using `.$type()` + ### Adding Cache Types 1. Add cache key to `cache/cacheSchemas.ts` 2. Define value type in `cache/cacheValueTypes.ts` diff --git a/packages/shared/data/types/message.ts b/packages/shared/data/types/message.ts new file mode 100644 index 0000000000..2c67d818e2 --- /dev/null +++ b/packages/shared/data/types/message.ts @@ -0,0 +1,171 @@ +/** + * Message Statistics - combines token usage and performance metrics + * Replaces the separate `usage` and `metrics` fields + */ +export interface MessageStats { + // Token consumption (from API response) + promptTokens?: number + completionTokens?: number + totalTokens?: number + thoughtsTokens?: number + + // Cost (calculated at message completion time) + cost?: number + + // Performance metrics (measured locally) + timeFirstTokenMs?: number + timeCompletionMs?: number + timeThinkingMs?: number +} + +// ============================================================================ +// Message Data +// ============================================================================ + +/** + * Message data field structure + * This is the type for the `data` column in the message table + */ +export interface MessageData { + blocks: MessageDataBlock[] +} + +//FIXME [v2] 注意,以下类型只是占位,接口未稳定,随时会变 + +// ============================================================================ +// Message Block +// ============================================================================ + +export enum BlockType { + UNKNOWN = 'unknown', + MAIN_TEXT = 'main_text', + THINKING = 'thinking', + TRANSLATION = 'translation', + IMAGE = 'image', + CODE = 'code', + TOOL = 'tool', + FILE = 'file', + ERROR = 'error', + CITATION = 'citation', + VIDEO = 'video', + COMPACT = 'compact' +} + +/** + * Base message block data structure + */ +export interface BaseBlock { + type: BlockType + createdAt: number // timestamp + updatedAt?: number + modelId?: string + metadata?: Record + error?: SerializedErrorData +} + +/** + * Serialized error for storage + */ +export interface SerializedErrorData { + name?: string + message: string + code?: string + stack?: string + cause?: unknown +} + +// Block type specific interfaces + +export interface UnknownBlock extends BaseBlock { + type: BlockType.UNKNOWN + content?: string +} + +export interface MainTextBlock extends BaseBlock { + type: BlockType.MAIN_TEXT + content: string + knowledgeBaseIds?: string[] + citationReferences?: { + citationBlockId?: string + citationBlockSource?: string + }[] +} + +export interface ThinkingBlock extends BaseBlock { + type: BlockType.THINKING + content: string + thinkingMs: number +} + +export interface TranslationBlock extends BaseBlock { + type: BlockType.TRANSLATION + content: string + sourceBlockId?: string + sourceLanguage?: string + targetLanguage: string +} + +export interface CodeBlock extends BaseBlock { + type: BlockType.CODE + content: string + language: string +} + +export interface ImageBlock extends BaseBlock { + type: BlockType.IMAGE + url?: string + fileId?: string +} + +export interface ToolBlock extends BaseBlock { + type: BlockType.TOOL + toolId: string + toolName?: string + arguments?: Record + content?: string | object +} + +export interface CitationBlock extends BaseBlock { + type: BlockType.CITATION + responseData?: unknown + knowledgeData?: unknown + memoriesData?: unknown +} + +export interface FileBlock extends BaseBlock { + type: BlockType.FILE + fileId: string +} + +export interface VideoBlock extends BaseBlock { + type: BlockType.VIDEO + url?: string + filePath?: string +} + +export interface ErrorBlock extends BaseBlock { + type: BlockType.ERROR +} + +export interface CompactBlock extends BaseBlock { + type: BlockType.COMPACT + content: string + compactedContent: string +} + +/** + * Union type of all message block data types + */ +export type MessageDataBlock = + | UnknownBlock + | MainTextBlock + | ThinkingBlock + | TranslationBlock + | CodeBlock + | ImageBlock + | ToolBlock + | CitationBlock + | FileBlock + | VideoBlock + | ErrorBlock + | CompactBlock diff --git a/src/main/data/README.md b/src/main/data/README.md index 7efff10113..be16e72bf3 100644 --- a/src/main/data/README.md +++ b/src/main/data/README.md @@ -239,7 +239,7 @@ import { dataApiService } from '@/data/DataApiService' ### Adding Database Tables 1. Create schema in `db/schemas/{tableName}.ts` -2. Generate migration: `yarn run migrations:generate` +2. Generate migration: `yarn run db:migrations:generate` 3. Add seeding data in `db/seeding/` if needed 4. Decide: Repository pattern or direct Drizzle? - Complex domain → Create repository in `repositories/` diff --git a/src/main/data/db/schemas/message.ts b/src/main/data/db/schemas/message.ts index d5a644bcce..91692ebd3f 100644 --- a/src/main/data/db/schemas/message.ts +++ b/src/main/data/db/schemas/message.ts @@ -1,3 +1,4 @@ +import type { MessageData, MessageStats } from '@shared/data/types/message' import { sql } from 'drizzle-orm' import { check, index, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core' @@ -37,11 +38,9 @@ export const messageTable = sqliteTable( // Preserved model info (provider, name) modelMeta: text({ mode: 'json' }), // Main content - contains blocks[], mentions, etc. - data: text({ mode: 'json' }).notNull(), - // Token usage statistics - usage: text({ mode: 'json' }), - // Performance metrics - metrics: text({ mode: 'json' }), + data: text({ mode: 'json' }).$type().notNull(), + // Statistics: token usage, performance metrics, etc. + stats: text({ mode: 'json' }).$type(), // Trace ID for tracking traceId: text(), // Searchable text extracted from data.blocks (populated by trigger, used for FTS5) diff --git a/src/renderer/src/types/newMessage.ts b/src/renderer/src/types/newMessage.ts index ef7179527d..4d63c2a8b4 100644 --- a/src/renderer/src/types/newMessage.ts +++ b/src/renderer/src/types/newMessage.ts @@ -1,3 +1,5 @@ +//TODO [v2] 类型将转移至 packages/shared/data/types/message.ts。 转移后此文件将废弃(deprecated) + import type { CompletionUsage } from '@cherrystudio/openai/resources' import type { ProviderMetadata } from 'ai'