@allbluecn/database 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +661 -0
  2. package/dist/get-prisma.d.ts +1 -0
  3. package/dist/get-prisma.js +7 -0
  4. package/generated/browser.ts +60 -0
  5. package/generated/client.ts +60 -0
  6. package/generated/commonInputTypes.ts +106 -46
  7. package/generated/internal/class.ts +124 -4
  8. package/generated/internal/prismaNamespace.ts +1121 -25
  9. package/generated/internal/prismaNamespaceBrowser.ts +202 -6
  10. package/generated/models/AiProviderConfig.ts +100 -1
  11. package/generated/models/AiStreamChunk.ts +1159 -0
  12. package/generated/models/AiUsageLog.ts +91 -31
  13. package/generated/models/Blob.ts +1428 -0
  14. package/generated/models/BusinessAgentBinding.ts +1553 -0
  15. package/generated/models/ChatInterrupt.ts +42 -1
  16. package/generated/models/ChatMessage.ts +58 -29
  17. package/generated/models/ChatPersistenceMeta.ts +1121 -0
  18. package/generated/models/ChatRun.ts +166 -1
  19. package/generated/models/ChatThread.ts +294 -1
  20. package/generated/models/CodeSnippet.ts +1555 -0
  21. package/generated/models/DesktopSetting.ts +1059 -0
  22. package/generated/models/GenerationRun.ts +193 -1
  23. package/generated/models/HarnessPlugin.ts +1677 -0
  24. package/generated/models/HarnessWorkspace.ts +1650 -0
  25. package/generated/models/InvitationCode.ts +0 -8
  26. package/generated/models/Plan.ts +115 -1
  27. package/generated/models/SandboxInstance.ts +1277 -0
  28. package/generated/models/SystemPromptTemplate.ts +1583 -0
  29. package/generated/models/SystemPromptVersion.ts +1459 -0
  30. package/generated/models/User.ts +4524 -866
  31. package/generated/models/UserAgent.ts +250 -1
  32. package/generated/models/Workspace.ts +3 -1
  33. package/generated/models/WorkspaceFile.ts +1535 -0
  34. package/generated/models.ts +12 -0
  35. package/generated-sqlite/browser.ts +60 -0
  36. package/generated-sqlite/client.ts +60 -0
  37. package/generated-sqlite/commonInputTypes.ts +192 -78
  38. package/generated-sqlite/internal/class.ts +124 -4
  39. package/generated-sqlite/internal/prismaNamespace.ts +1135 -25
  40. package/generated-sqlite/internal/prismaNamespaceBrowser.ts +202 -6
  41. package/generated-sqlite/models/AiProviderConfig.ts +100 -1
  42. package/generated-sqlite/models/AiStreamChunk.ts +1157 -0
  43. package/generated-sqlite/models/AiUsageLog.ts +91 -31
  44. package/generated-sqlite/models/Blob.ts +1425 -0
  45. package/generated-sqlite/models/BusinessAgentBinding.ts +1549 -0
  46. package/generated-sqlite/models/ChatInterrupt.ts +42 -1
  47. package/generated-sqlite/models/ChatMessage.ts +58 -29
  48. package/generated-sqlite/models/ChatPersistenceMeta.ts +1119 -0
  49. package/generated-sqlite/models/ChatRun.ts +174 -1
  50. package/generated-sqlite/models/ChatThread.ts +293 -1
  51. package/generated-sqlite/models/CodeSnippet.ts +1552 -0
  52. package/generated-sqlite/models/DesktopSetting.ts +1057 -0
  53. package/generated-sqlite/models/GenerationRun.ts +193 -1
  54. package/generated-sqlite/models/HarnessPlugin.ts +1674 -0
  55. package/generated-sqlite/models/HarnessWorkspace.ts +1647 -0
  56. package/generated-sqlite/models/InvitationCode.ts +0 -8
  57. package/generated-sqlite/models/PageVersion.ts +0 -8
  58. package/generated-sqlite/models/Plan.ts +115 -1
  59. package/generated-sqlite/models/SandboxInstance.ts +1283 -0
  60. package/generated-sqlite/models/SystemPromptTemplate.ts +1581 -0
  61. package/generated-sqlite/models/SystemPromptVersion.ts +1456 -0
  62. package/generated-sqlite/models/User.ts +3778 -708
  63. package/generated-sqlite/models/UserAgent.ts +250 -1
  64. package/generated-sqlite/models/Workspace.ts +3 -1
  65. package/generated-sqlite/models/WorkspaceFile.ts +1532 -0
  66. package/generated-sqlite/models.ts +12 -0
  67. package/get-prisma.ts +6 -0
  68. package/index.ts +11 -6
  69. package/migrations/20260914002427_ai_p0_durable_runs_meta/migration.sql +15 -0
  70. package/migrations/20260914041010_ai_p0_interrupt_requested_at/migration.sql +15 -0
  71. package/migrations/20260914041909_ai_p0_message_tool_call_id/migration.sql +2 -0
  72. package/migrations/20260914042448_ai_p0_message_content_json/migration.sql +27 -0
  73. package/migrations/20260914150229_harness_plugin/migration.sql +27 -0
  74. package/migrations/20260914174404_prompt_platform_agents/migration.sql +67 -0
  75. package/migrations/20260915090000_add_memory_facts/migration.sql +22 -0
  76. package/migrations/20260915124417_ai_p3_sandbox_durable/migration.sql +48 -0
  77. package/migrations/20260915150034_sandbox_instance_updatedat_bigint/migration.sql +2 -0
  78. package/migrations/20260915154000_add_code_snippets/migration.sql +31 -0
  79. package/migrations/20260916090000_ai_usage_log_nullable_workspace/migration.sql +10 -0
  80. package/migrations/20260916192752_add_ai_source_mode/migration.sql +13 -0
  81. package/migrations/20260917044512_harness_workspace/migration.sql +47 -0
  82. package/migrations/20260917100000_add_media_plan_limits/migration.sql +3 -0
  83. package/migrations/20260917163433_add_generation_run_linked_target/migration.sql +2 -0
  84. package/migrations/20260920050606_add_blob_table/migration.sql +17 -0
  85. package/migrations/20260920093412_add_byteplus_voice_fields/migration.sql +3 -0
  86. package/package.json +8 -3
  87. package/schema.prisma +321 -88
  88. package/schema.sqlite.prisma +779 -546
package/schema.prisma CHANGED
@@ -44,6 +44,7 @@ model User {
44
44
  aiProvider String? // "openrouter" | "openai"
45
45
  aiApiKey String? // 用户 AI API Key(TODO: 加密存储)
46
46
  aiModel String? // 默认 "openai/gpt-4o-mini"
47
+ aiSourceMode String? // 模型来源模式:hosted | local-agent | byok;null = 未选择(默认 byok 行为)
47
48
  locale String? // 用户语言偏好(zh / en),null 表示未设置
48
49
 
49
50
  storyDisplayOptions Json? // Story Display Options 个人偏好(URL 无参数时的默认值,跨设备持久化)
@@ -75,48 +76,53 @@ model User {
75
76
  articleFavorites ArticleFavorite[]
76
77
  anyhubApps AnyHubApp[]
77
78
  anyhubMarketApps AnyHubMarketApp[]
78
- reviewedAnyhubRecommendations AnyHubRecommendation[] @relation("reviewedAnyhubRecommendations")
79
+ reviewedAnyhubRecommendations AnyHubRecommendation[] @relation("reviewedAnyhubRecommendations")
79
80
  anyhubRecommenders AnyHubRecommender[]
80
81
  prdVersions PRDVersion[]
81
82
  reviewComments ReviewComment[]
82
83
  comments Comment[]
83
84
  commentIgnores CommentIgnore[]
84
- reviews Review[] @relation("reviewer")
85
+ reviews Review[] @relation("reviewer")
85
86
  designProjects DesignProject[]
86
- storiesCreated Story[] @relation("storyCreator")
87
- storiesAssigned Story[] @relation("storyAssignee")
88
- storiesEdited Story[] @relation("storyEditor")
89
- iterationsCreated Iteration[] @relation("iterationCreator")
90
- labelsCreated Label[] @relation("labelCreator")
91
- storyActivities StoryActivity[] @relation("storyActivityUser")
92
- storyComments StoryComment[] @relation("storyCommentUser")
93
- storyReactions StoryReaction[] @relation("storyReactionUser")
94
- commentReactions CommentReaction[] @relation("commentReactionUser")
87
+ storiesCreated Story[] @relation("storyCreator")
88
+ storiesAssigned Story[] @relation("storyAssignee")
89
+ storiesEdited Story[] @relation("storyEditor")
90
+ iterationsCreated Iteration[] @relation("iterationCreator")
91
+ labelsCreated Label[] @relation("labelCreator")
92
+ storyActivities StoryActivity[] @relation("storyActivityUser")
93
+ storyComments StoryComment[] @relation("storyCommentUser")
94
+ storyReactions StoryReaction[] @relation("storyReactionUser")
95
+ commentReactions CommentReaction[] @relation("commentReactionUser")
95
96
  storyFilterViews StoryFilterView[]
96
97
  chatThreads ChatThread[]
97
98
  aiProviderConfigs AiProviderConfig[]
98
99
  agentConversations AgentConversation[]
99
- ownedProjects Project[] @relation("projectOwner")
100
+ ownedProjects Project[] @relation("projectOwner")
100
101
  projectMemberships ProjectMember[]
101
102
  projectActivities ProjectActivity[]
102
- ownedWorkspaces Workspace[] @relation("workspaceOwner")
103
- workspaceMemberships TeamMembership[] @relation("teamOwner")
104
- teamJoined TeamMembership? @relation("teamMember")
103
+ ownedWorkspaces Workspace[] @relation("workspaceOwner")
104
+ workspaceMemberships TeamMembership[] @relation("teamOwner")
105
+ teamJoined TeamMembership? @relation("teamMember")
105
106
  workspaceMembers WorkspaceMember[]
106
- sentInvitations TeamInvitation[] @relation("invitationOwner")
107
- ownedJoinRequests TeamJoinRequest[] @relation("joinRequestOwner")
108
- applicantJoinRequests TeamJoinRequest[] @relation("joinRequestApplicant")
107
+ sentInvitations TeamInvitation[] @relation("invitationOwner")
108
+ ownedJoinRequests TeamJoinRequest[] @relation("joinRequestOwner")
109
+ applicantJoinRequests TeamJoinRequest[] @relation("joinRequestApplicant")
109
110
  aiUsageLogs AiUsageLog[]
110
111
  agents UserAgent[]
111
112
  skills UserSkill[]
112
113
  notifications Notification[]
113
114
  notificationPreference NotificationPreference?
114
115
 
115
- issuedLicenses LicenseKey[] @relation("LicenseIssuer")
116
- ssoMappings SsoMapping[]
117
- roleAssignments RoleAssignment[]
118
- subscription Subscription?
116
+ issuedLicenses LicenseKey[] @relation("LicenseIssuer")
117
+ ssoMappings SsoMapping[]
118
+ codeSnippets CodeSnippet[]
119
+ roleAssignments RoleAssignment[]
120
+ subscription Subscription?
119
121
  createdQuickDocs WorkspaceQuickDoc[]
122
+ plugins HarnessPlugin[]
123
+ harnessWorkspaces HarnessWorkspace[]
124
+ agentBindings BusinessAgentBinding[]
125
+ blobs Blob[]
120
126
 
121
127
  @@map("users")
122
128
  }
@@ -188,22 +194,22 @@ model ProjectMember {
188
194
 
189
195
  // 工作空间(项目的上一级容器)
190
196
  model Workspace {
191
- id String @id @default(cuid())
192
- name String
193
- icon String @default("folder")
194
- description String?
195
- pinnedToSidebar Boolean @default(false)
196
- ownerId String
197
- owner User @relation("workspaceOwner", fields: [ownerId], references: [id])
198
- projects Project[]
199
- members WorkspaceMember[]
200
- knowledgeBases KnowledgeBase[]
201
- workspaceKbLinks WorkspaceKnowledgeBase[]
202
- quickDocs WorkspaceQuickDoc[]
203
- usageRecords UsageRecord[]
204
- aiUsageLogs AiUsageLog[]
205
- createdAt DateTime @default(now())
206
- updatedAt DateTime @updatedAt
197
+ id String @id @default(cuid())
198
+ name String
199
+ icon String @default("folder")
200
+ description String?
201
+ pinnedToSidebar Boolean @default(false)
202
+ ownerId String
203
+ owner User @relation("workspaceOwner", fields: [ownerId], references: [id])
204
+ projects Project[]
205
+ members WorkspaceMember[]
206
+ knowledgeBases KnowledgeBase[]
207
+ workspaceKbLinks WorkspaceKnowledgeBase[]
208
+ quickDocs WorkspaceQuickDoc[]
209
+ usageRecords UsageRecord[]
210
+ aiUsageLogs AiUsageLog[]
211
+ createdAt DateTime @default(now())
212
+ updatedAt DateTime @updatedAt
207
213
 
208
214
  ssoProviders SsoProvider[]
209
215
  customRoles CustomRole[]
@@ -307,12 +313,13 @@ model ProjectActivity {
307
313
 
308
314
  // 对话线程(作为 TanStack AI persistence threadId)
309
315
  model ChatThread {
310
- id String @id @default(cuid())
311
- userId String
312
- title String?
313
- isArchived Boolean @default(false)
314
- createdAt DateTime @default(now())
315
- updatedAt DateTime @updatedAt
316
+ id String @id @default(cuid())
317
+ userId String
318
+ title String?
319
+ isArchived Boolean @default(false)
320
+ sandboxPolicy String @default("readonly")
321
+ createdAt DateTime @default(now())
322
+ updatedAt DateTime @updatedAt
316
323
 
317
324
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
318
325
  messages ChatMessage[]
@@ -321,6 +328,8 @@ model ChatThread {
321
328
  generations GenerationRun[]
322
329
  agentId String?
323
330
  agent UserAgent? @relation(fields: [agentId], references: [id])
331
+ workspaceId String?
332
+ workspace HarnessWorkspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
324
333
 
325
334
  @@index([userId, updatedAt])
326
335
  @@map("chat_threads")
@@ -328,14 +337,15 @@ model ChatThread {
328
337
 
329
338
  // 对话消息(TanStack AI messages store)
330
339
  model ChatMessage {
331
- id String @id @default(cuid())
332
- threadId String
333
- role String // "user" | "assistant" | "tool"
334
- content String @db.Text
335
- parts Json?
336
- thinking String? @db.Text
337
- citations Json?
338
- createdAt DateTime @default(now())
340
+ id String @id @default(cuid())
341
+ threadId String
342
+ role String // "user" | "assistant" | "tool"
343
+ content Json? // string | ContentPart[] | null — round-trip 无损
344
+ parts Json? // toolCalls(assistant 调用工具时)
345
+ thinking String? @db.Text
346
+ citations Json?
347
+ toolCallId String?
348
+ createdAt DateTime @default(now())
339
349
 
340
350
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
341
351
 
@@ -345,15 +355,18 @@ model ChatMessage {
345
355
 
346
356
  // 运行记录(TanStack AI runs store)
347
357
  model ChatRun {
348
- id String @id @default(cuid())
349
- threadId String
350
- userId String
351
- status String // running | completed | failed | aborted | interrupted
352
- startedAt DateTime @default(now())
353
- finishedAt DateTime?
354
- detachedSince DateTime?
355
- usage Json?
356
- error String? @db.Text
358
+ id String @id @default(cuid())
359
+ threadId String
360
+ userId String
361
+ status String // running | completed | failed | aborted | interrupted
362
+ startedAt DateTime @default(now())
363
+ finishedAt DateTime?
364
+ detachedSince DateTime?
365
+ usage Json?
366
+ error String? @db.Text
367
+ sandboxKey String?
368
+ cancelRequested Boolean?
369
+ driverEpoch Int?
357
370
 
358
371
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
359
372
  interrupts ChatInterrupt[]
@@ -365,17 +378,18 @@ model ChatRun {
365
378
 
366
379
  // 中断记录(TanStack AI interrupts store)
367
380
  model ChatInterrupt {
368
- id String @id @default(cuid())
369
- runId String
370
- threadId String
371
- userId String
372
- kind String // tool-approval | generic
373
- toolName String?
374
- state String // pending | resolved | cancelled
375
- payload Json?
376
- resolution Json?
377
- createdAt DateTime @default(now())
378
- resolvedAt DateTime?
381
+ id String @id @default(cuid())
382
+ runId String
383
+ threadId String
384
+ userId String
385
+ kind String // tool-approval | generic
386
+ toolName String?
387
+ state String // pending | resolved | cancelled
388
+ payload Json?
389
+ resolution Json?
390
+ requestedAt DateTime @default(now())
391
+ createdAt DateTime @default(now())
392
+ resolvedAt DateTime?
379
393
 
380
394
  run ChatRun @relation(fields: [runId], references: [id], onDelete: Cascade)
381
395
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
@@ -385,6 +399,100 @@ model ChatInterrupt {
385
399
  @@map("chat_interrupts")
386
400
  }
387
401
 
402
+ // TanStack AI persistence metadata store(compaction checkpoint / ChatProjection 等)
403
+ // namespace 由消费方(中间件)自带,如 "compaction"、"projection.todos"
404
+ model ChatPersistenceMeta {
405
+ namespace String
406
+ key String
407
+ value Json
408
+ updatedAt DateTime @updatedAt
409
+
410
+ @@unique([namespace, key])
411
+ @@map("chat_persistence_meta")
412
+ }
413
+
414
+ // dsh(DeepSeek-Harness)兼容插件(设计 v8 ADR 21:插件定义 DB 持久化,运行态随页面)
415
+ model HarnessPlugin {
416
+ id String @id @default(cuid())
417
+ userId String
418
+ name String
419
+ purpose String @db.Text
420
+ codeHost String? @db.Text
421
+ codeClient String? @db.Text
422
+ // plugin_define 求值后插件经 harness.defineTool 上报的工具定义(JSON Schema 数组)
423
+ tools Json @default("[]")
424
+ version Int @default(1)
425
+ // defined | running | stopped | error
426
+ status String @default("defined")
427
+ lastError String? @db.Text
428
+ createdAt DateTime @default(now())
429
+ updatedAt DateTime @updatedAt
430
+ isDeleted Boolean @default(false)
431
+
432
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
433
+
434
+ @@unique([userId, name])
435
+ @@index([userId])
436
+ @@map("harness_plugins")
437
+ }
438
+
439
+ // P2 提示词平台:系统提示词模板(DB 版本化,服务端唯一来源)
440
+ model SystemPromptTemplate {
441
+ id String @id @default(cuid())
442
+ key String @unique
443
+ name String
444
+ description String?
445
+ sections Json @default("[]")
446
+ variables Json @default("[]")
447
+ version Int @default(1)
448
+ isActive Boolean @default(true)
449
+ isProtected Boolean @default(false)
450
+ updatedBy String?
451
+ createdAt DateTime @default(now())
452
+ updatedAt DateTime @updatedAt
453
+ versions SystemPromptVersion[]
454
+
455
+ @@map("system_prompt_templates")
456
+ }
457
+
458
+ // P2 提示词平台:系统提示词模板的历史版本快照。
459
+ // 设计取舍:仅快照 sections(真正发给 LLM 的提示词主体);variables 作为
460
+ // 元数据随模板演进不纳入版本管理——回滚只还原提示词文本,变量声明由模板表当前值兜底。
461
+ model SystemPromptVersion {
462
+ id String @id @default(cuid())
463
+ templateId String
464
+ template SystemPromptTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
465
+ version Int
466
+ sections Json
467
+ note String?
468
+ createdBy String?
469
+ createdAt DateTime @default(now())
470
+
471
+ @@unique([templateId, version])
472
+ @@map("system_prompt_versions")
473
+ }
474
+
475
+ // P2 异构多智能体:板块 agent 绑定(三级链第①级:板块绑定 > 用户默认 > 系统默认)。
476
+ // 设计取舍:① 硬删(无独立业务生命周期,upsert/deleteMany 管理)而非 isDeleted 软删;
477
+ // ② workspaceId 为跨工作区绑定的预留字段,当前不建 relation——bizKey 已表达业务作用域,
478
+ // 工作区级绑定待 P3 启用时再补 relation + 索引。
479
+ model BusinessAgentBinding {
480
+ id String @id @default(cuid())
481
+ userId String
482
+ bizKey String
483
+ agentId String
484
+ workspaceId String?
485
+ createdAt DateTime @default(now())
486
+ updatedAt DateTime @updatedAt
487
+
488
+ agent UserAgent @relation(fields: [agentId], references: [id], onDelete: Cascade)
489
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
490
+
491
+ @@unique([userId, bizKey])
492
+ @@index([userId])
493
+ @@map("business_agent_bindings")
494
+ }
495
+
388
496
  // 媒体生成记录(占位,本轮建表不接入业务)
389
497
  model GenerationRun {
390
498
  id String @id @default(cuid())
@@ -395,9 +503,15 @@ model GenerationRun {
395
503
  input Json?
396
504
  result Json?
397
505
  artifactId String?
506
+ activity String? // 官方 GenerationRunRecord 视角:chat|image|audio|tts|video|transcription|sandbox
507
+ provider String?
508
+ model String?
509
+ artifacts Json?
510
+ usage Json?
398
511
  error String? @db.Text
399
512
  startedAt DateTime @default(now())
400
513
  finishedAt DateTime?
514
+ linkedTarget Json? // P4d 回流标记 { kind: story|kb|prd, targetId, at },最近一次(覆盖)
401
515
 
402
516
  thread ChatThread @relation(fields: [threadId], references: [id], onDelete: Cascade)
403
517
 
@@ -517,7 +631,7 @@ model OAuthProviderConfig {
517
631
  id String @id @default(cuid())
518
632
  provider String @unique
519
633
  clientId String
520
- clientSecret String // AES-256-GCM 密文
634
+ clientSecret String // AES-256-GCM 密文
521
635
  enabled Boolean @default(false)
522
636
  extra Json?
523
637
  createdAt DateTime @default(now())
@@ -592,10 +706,10 @@ model KnowledgeBase {
592
706
  createdAt DateTime @default(now())
593
707
  updatedAt DateTime @updatedAt
594
708
 
595
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
596
- workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
597
- documents KnowledgeDocument[]
598
- projectLinks ProjectKnowledgeBase[]
709
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
710
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: SetNull)
711
+ documents KnowledgeDocument[]
712
+ projectLinks ProjectKnowledgeBase[]
599
713
  workspaceLinks WorkspaceKnowledgeBase[]
600
714
 
601
715
  @@index([userId])
@@ -620,11 +734,11 @@ model KnowledgeDocument {
620
734
  createdAt DateTime @default(now())
621
735
  updatedAt DateTime @updatedAt
622
736
 
623
- kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
624
- parent KnowledgeDocument? @relation("DocumentTree", fields: [parentId], references: [id], onDelete: SetNull)
625
- children KnowledgeDocument[] @relation("DocumentTree")
626
- creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
627
- linkedStories StoryDocLink[] @relation("DocStoryLinks")
737
+ kb KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
738
+ parent KnowledgeDocument? @relation("DocumentTree", fields: [parentId], references: [id], onDelete: SetNull)
739
+ children KnowledgeDocument[] @relation("DocumentTree")
740
+ creator User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
741
+ linkedStories StoryDocLink[] @relation("DocStoryLinks")
628
742
  workspaceQuickDocs WorkspaceQuickDoc[]
629
743
 
630
744
  @@index([kbId])
@@ -1294,9 +1408,12 @@ model AiProviderConfig {
1294
1408
  providerId String // 业务 providerId,软关联 AiProvider.providerId(不设外键 cascade,避免 admin 删除丢失用户配置)
1295
1409
  apiKey String? @db.Text // 加密存储 TODO
1296
1410
  baseUrl String?
1411
+ voiceApiKey String? @db.Text // BytePlus Voice 独立 API key(speech/transcription 用,与 Ark apiKey 分开)
1412
+ voiceBaseUrl String? // BytePlus Voice Base URL(默认 fallback 到 baseUrl)
1297
1413
  enabled Boolean @default(false) // 用户级开关:是否在对话模型选择器中暴露
1298
1414
  models Json? // string[] 用户启用的模型 ID(有序,顺序 = 模型选择器展示顺序)
1299
1415
  customModels Json? // AiModelMeta[] 用户私有的自定义/刷新获取的模型元数据,与 AiProvider.models 取并集按 id 去重
1416
+ agentMeta Json? // 模式2 本地 Agent 元数据:{ binary, resolvedPath, version, auth, workspaceDir, detectedAt };不存任何密钥
1300
1417
  createdAt DateTime @default(now())
1301
1418
  updatedAt DateTime @updatedAt
1302
1419
 
@@ -1918,8 +2035,11 @@ model Plan {
1918
2035
  providerSeatPriceIdUsd String?
1919
2036
  providerSeatPriceIdCny String?
1920
2037
 
1921
- agentQuota Int?
1922
- skillQuota Int?
2038
+ agentQuota Int?
2039
+ skillQuota Int?
2040
+ sandboxMinutesMonthly Int?
2041
+ mediaGenerationsMonthly Int?
2042
+ galleryStorageMb Int?
1923
2043
 
1924
2044
  subscriptions Subscription[]
1925
2045
 
@@ -1995,11 +2115,14 @@ enum UsageMetric {
1995
2115
  /// AI 用量明细(按次扣减 + 成本审计)
1996
2116
  model AiUsageLog {
1997
2117
  id String @id @default(cuid())
1998
- workspaceId String
1999
- workspace Workspace @relation(fields: [workspaceId], references: [id])
2118
+ // 可空:配额按 userId 计(见 ResourceRegistry.sandboxMinutesMonthly),工作区只作归属维度。
2119
+ // 不可空会让「尚无工作区的用户」无法落计量行,等于沙箱计费闸可被绕过。
2120
+ workspaceId String?
2121
+ workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Restrict)
2000
2122
  userId String
2001
2123
  user User @relation(fields: [userId], references: [id])
2002
2124
  source String @default("byok")
2125
+ activity String? // 区分 chat/sandbox/image...(P3 计费维度;null = 既有 byok 语义)
2003
2126
  provider String
2004
2127
  model String
2005
2128
  inputTokens Int @default(0)
@@ -2211,9 +2334,12 @@ model UserAgent {
2211
2334
  createdAt DateTime @default(now())
2212
2335
  updatedAt DateTime @updatedAt
2213
2336
  isDeleted Boolean @default(false)
2337
+ isDefault Boolean @default(false)
2338
+ harnessKind String? // code preset:claude-code | codex | acp | opencode(null = 普通对话 agent)
2214
2339
 
2215
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2216
- threads ChatThread[]
2340
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2341
+ threads ChatThread[]
2342
+ agentBindings BusinessAgentBinding[]
2217
2343
 
2218
2344
  @@index([userId])
2219
2345
  @@map("user_agents")
@@ -2321,3 +2447,110 @@ model IterationAutoSchedule {
2321
2447
 
2322
2448
  @@map("iteration_auto_schedules")
2323
2449
  }
2450
+
2451
+ // 编排模式可复用片段:用户保存的跨请求编排逻辑。运行时经 getSnippetBindings
2452
+ // 暴露为 snippet_<name> 绑定,片段函数体在嵌套沙箱内执行并可调用 external_* 工具。
2453
+ // 片段本身不豁免归属校验,execute 只在服务端执行,不进客户端 bundle。
2454
+ model CodeSnippet {
2455
+ id String @id @default(cuid())
2456
+ userId String
2457
+ name String
2458
+ title String
2459
+ description String
2460
+ params Json @default("{}")
2461
+ code String @db.Text
2462
+ enabled Boolean @default(true)
2463
+ createdAt DateTime @default(now())
2464
+ updatedAt DateTime @updatedAt
2465
+ isDeleted Boolean @default(false)
2466
+
2467
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2468
+
2469
+ @@unique([userId, name])
2470
+ @@index([userId, enabled, isDeleted])
2471
+ @@map("code_snippets")
2472
+ }
2473
+
2474
+ // P3 durable runs:沙箱实例映射(SandboxInstanceStore 的 Prisma 实现,key = computeSandboxKey 复合键)
2475
+ model SandboxInstance {
2476
+ key String @id
2477
+ provider String
2478
+ providerSandboxId String
2479
+ latestSnapshotId String?
2480
+ threadId String
2481
+ latestRunId String?
2482
+ updatedAt BigInt // epoch ms(契约要求;int4 上限 2.1e9 装不下毫秒,须 int8)
2483
+ createdAt DateTime @default(now())
2484
+
2485
+ @@index([threadId])
2486
+ @@map("sandbox_instances")
2487
+ }
2488
+
2489
+ // P3 durable runs:PG StreamDurability 事件日志(每 chunk 一行,id=offset)
2490
+ model AiStreamChunk {
2491
+ id BigInt @id @default(autoincrement())
2492
+ runId String
2493
+ chunk Json
2494
+ createdAt DateTime @default(now())
2495
+
2496
+ @@index([runId, id])
2497
+ @@map("ai_stream_chunks")
2498
+ }
2499
+
2500
+ model DesktopSetting {
2501
+ key String @id // "aiSourceMode" | "localAgentConfig"
2502
+ value Json
2503
+
2504
+ @@map("desktop_settings")
2505
+ }
2506
+
2507
+ /// Harness 工作区(云端持久化文件区 + 业务数据视图入口)
2508
+ model HarnessWorkspace {
2509
+ id String @id @default(cuid())
2510
+ name String
2511
+ ownerId String
2512
+ kind String @default("cloud") // "cloud" | "local-meta"(本地挂载只存元数据)
2513
+ createdAt DateTime @default(now())
2514
+ updatedAt DateTime @updatedAt
2515
+
2516
+ owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
2517
+ files WorkspaceFile[]
2518
+ threads ChatThread[]
2519
+
2520
+ @@index([ownerId, updatedAt])
2521
+ @@map("harness_workspaces")
2522
+ }
2523
+
2524
+ /// 工作区文件(上传文件 + AI 生成物 + 沙箱产出)
2525
+ model WorkspaceFile {
2526
+ id String @id @default(cuid())
2527
+ workspaceId String
2528
+ path String // 相对路径,如 "src/index.ts"
2529
+ mimeType String @default("application/octet-stream")
2530
+ size Int @default(0)
2531
+ content String? @db.Text // 小文件内联(≤256KB);大文件走 blob 存储(P4c)
2532
+ source String @default("upload") // "upload" | "ai-generated" | "sandbox"
2533
+ createdAt DateTime @default(now())
2534
+ updatedAt DateTime @updatedAt
2535
+
2536
+ workspace HarnessWorkspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
2537
+
2538
+ @@unique([workspaceId, path])
2539
+ @@index([workspaceId])
2540
+ @@map("workspace_files")
2541
+ }
2542
+
2543
+ // AI 附件二进制存储(P5 Wave 2)
2544
+ model Blob {
2545
+ id String @id @default(cuid())
2546
+ mimeType String
2547
+ bytes Bytes
2548
+ size Int
2549
+ userId String
2550
+ createdAt DateTime @default(now())
2551
+
2552
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
2553
+
2554
+ @@index([userId])
2555
+ @@map("blobs")
2556
+ }