| 1 | import { AccountType, createPaginationVo, createZodDto } from '@yikart/common' |
| 2 | import { ContentGenerationTaskStatus } from '@yikart/mongodb' |
| 3 | import { z } from 'zod' |
| 4 | |
| 5 | export enum AgentMessageType { |
| 6 | Assistant = 'assistant', |
| 7 | User = 'user', |
| 8 | Result = 'result', |
| 9 | System = 'system', |
| 10 | StreamEvent = 'stream_event', |
| 11 | ToolProgress = 'tool_progress', |
| 12 | AuthStatus = 'auth_status', |
| 13 | KeepAlive = 'keep_alive', |
| 14 | Init = 'init', |
| 15 | Complete = 'complete', |
| 16 | TitleUpdated = 'title_updated', |
| 17 | Error = 'error', |
| 18 | } |
| 19 | |
| 20 | export const ContentGenerationMediaVoSchema = z.object({ |
| 21 | type: z.enum(['IMAGE', 'VIDEO']), |
| 22 | url: z.string(), |
| 23 | thumbUrl: z.string().optional(), |
| 24 | prompt: z.string().optional(), |
| 25 | }) |
| 26 | export class ContentGenerationMediaVo extends createZodDto(ContentGenerationMediaVoSchema) { } |
| 27 | |
| 28 | // MediaOnly result schema (single object only) |
| 29 | const MediaOnlyBaseSchema = z.object({ |
| 30 | type: z.literal('mediaOnly'), |
| 31 | medias: z.array(ContentGenerationMediaVoSchema), |
| 32 | }) |
| 33 | |
| 34 | const MediaOnlyNoneActionSchema = MediaOnlyBaseSchema.extend({ |
| 35 | action: z.literal('none'), |
| 36 | }) |
| 37 | |
| 38 | const MediaOnlyNavigateToMediaActionSchema = MediaOnlyBaseSchema.extend({ |
| 39 | action: z.literal('navigateToMedia'), |
| 40 | mediaId: z.string(), |
| 41 | groupId: z.string(), |
| 42 | }) |
| 43 | |
| 44 | const MediaOnlyResultSchema = z.discriminatedUnion('action', [ |
| 45 | MediaOnlyNoneActionSchema, |
| 46 | MediaOnlyNavigateToMediaActionSchema, |
| 47 | ]) |
| 48 | |
| 49 | // FullContent result schema (array only) |
| 50 | // Base fields for each array element |
| 51 | const FullContentElementBaseSchema = z.object({ |
| 52 | type: z.literal('fullContent'), |
| 53 | title: z.string(), |
| 54 | description: z.string(), |
| 55 | tags: z.array(z.string()), |
| 56 | medias: z.array(ContentGenerationMediaVoSchema), |
| 57 | }) |
| 58 | |
| 59 | // Action: none (platform not needed) |
| 60 | const FullContentNoneActionSchema = FullContentElementBaseSchema.extend({ |
| 61 | action: z.literal('none'), |
| 62 | platform: z.enum(AccountType).optional(), |
| 63 | flowId: z.string().optional(), |
| 64 | }) |
| 65 | |
| 66 | // Action: navigateToDraft (platform not needed) |
| 67 | const FullContentNavigateToDraftActionSchema = FullContentElementBaseSchema.extend({ |
| 68 | action: z.literal('navigateToDraft'), |
| 69 | groupId: z.string(), |
| 70 | platform: z.enum(AccountType).optional(), |
| 71 | }) |
| 72 | |
| 73 | // Action: navigateToMedia (platform not needed) |
| 74 | const FullContentNavigateToMediaActionSchema = FullContentElementBaseSchema.extend({ |
| 75 | action: z.literal('navigateToMedia'), |
| 76 | mediaId: z.string(), |
| 77 | groupId: z.string(), |
| 78 | platform: z.enum(AccountType).optional(), |
| 79 | }) |
| 80 | |
| 81 | // Action: createChannel (platform required) |
| 82 | const FullContentCreateChannelActionSchema = FullContentElementBaseSchema.extend({ |
| 83 | action: z.literal('createChannel'), |
| 84 | platform: z.enum(AccountType), // required |
| 85 | errorMessage: z.string().optional(), |
| 86 | }) |
| 87 | |
| 88 | // Action: updateChannel (platform required) |
| 89 | const FullContentUpdateChannelActionSchema = FullContentElementBaseSchema.extend({ |
| 90 | action: z.literal('updateChannel'), |
| 91 | platform: z.enum(AccountType), // required |
| 92 | accountId: z.string().optional(), |
| 93 | errorMessage: z.string().optional(), |
| 94 | }) |
| 95 | |
| 96 | // Action: navigateToPublish (platform required) |
| 97 | const FullContentNavigateToPublishActionSchema = FullContentElementBaseSchema.extend({ |
| 98 | action: z.literal('navigateToPublish'), |
| 99 | platform: z.enum(AccountType), // required |
| 100 | accountId: z.string().optional(), |
| 101 | publishTime: z.iso.datetime().optional(), |
| 102 | topics: z.array(z.string()).optional(), |
| 103 | errorMessage: z.string().optional(), |
| 104 | }) |
| 105 | |
| 106 | // FullContent single element union |
| 107 | const FullContentElementSchema = z.discriminatedUnion('action', [ |
| 108 | FullContentNoneActionSchema, |
| 109 | FullContentNavigateToDraftActionSchema, |
| 110 | FullContentNavigateToMediaActionSchema, |
| 111 | FullContentCreateChannelActionSchema, |
| 112 | FullContentUpdateChannelActionSchema, |
| 113 | FullContentNavigateToPublishActionSchema, |
| 114 | ]) |
| 115 | |
| 116 | // FullContent result is an array (minimum 1 element) |
| 117 | const FullContentResultSchema = z.array(FullContentElementSchema).min(1) |
| 118 | |
| 119 | // Final union: mediaOnly (single object) OR fullContent (array) |
| 120 | export const ContentGenerationTaskResultUnionSchema = z.union([ |
| 121 | MediaOnlyResultSchema, |
| 122 | FullContentResultSchema, |
| 123 | ]) |
| 124 | |
| 125 | export const ContentGenerationTaskResultSchema = z.object({ |
| 126 | result: ContentGenerationTaskResultUnionSchema, |
| 127 | }) |
| 128 | |
| 129 | const APIUserMessageSchema = z.object({ |
| 130 | content: z.union([z.string(), z.array(z.unknown())]), // string | Array<ContentBlockParam> |
| 131 | role: z.enum(['user', 'assistant']), |
| 132 | }) |
| 133 | |
| 134 | const APIAssistantMessageSchema = z.object({ |
| 135 | id: z.string().optional(), |
| 136 | content: z.array(z.unknown()).optional(), // Array<BetaContentBlock> |
| 137 | model: z.string().optional(), |
| 138 | role: z.literal('assistant').optional(), |
| 139 | stop_reason: z.enum(['end_turn', 'max_tokens', 'stop_sequence', 'tool_use', 'pause_turn', 'refusal']).nullable().optional(), |
| 140 | stop_sequence: z.string().nullable().optional(), |
| 141 | type: z.literal('message').optional(), |
| 142 | usage: z.object({ |
| 143 | cache_creation: z.object({ |
| 144 | ephemeral_1h_input_tokens: z.number().optional(), |
| 145 | ephemeral_5m_input_tokens: z.number().optional(), |
| 146 | }).nullable().optional(), |
| 147 | cache_creation_input_tokens: z.number().nullable().optional(), |
| 148 | cache_read_input_tokens: z.number().nullable().optional(), |
| 149 | input_tokens: z.number().optional(), |
| 150 | output_tokens: z.number().optional(), |
| 151 | server_tool_use: z.object({ |
| 152 | web_search_requests: z.number(), |
| 153 | }).nullable().optional(), |
| 154 | service_tier: z.string().nullable().optional(), // 允许 service_tier 字段 |
| 155 | }).loose().optional(), // 使用 passthrough 允许额外字段 |
| 156 | container: z.unknown().nullable().optional(), // BetaContainer |
| 157 | context_management: z.unknown().nullable().optional(), // BetaContextManagementResponse |
| 158 | }).loose() // 允许额外字段 |
| 159 | |
| 160 | const NonNullableUsageSchema = z.object({ |
| 161 | cache_creation: z.object({ |
| 162 | ephemeral_1h_input_tokens: z.number(), |
| 163 | ephemeral_5m_input_tokens: z.number(), |
| 164 | }).optional(), |
| 165 | cache_creation_input_tokens: z.number().optional(), |
| 166 | cache_read_input_tokens: z.number().optional(), |
| 167 | input_tokens: z.number().optional(), |
| 168 | output_tokens: z.number().optional(), |
| 169 | server_tool_use: z.object({ |
| 170 | web_search_requests: z.number(), |
| 171 | }).optional(), |
| 172 | }) |
| 173 | |
| 174 | const RawMessageStreamEventSchema = z.discriminatedUnion('type', [ |
| 175 | z.object({ |
| 176 | type: z.literal('message_start'), |
| 177 | message: z.unknown(), |
| 178 | }), |
| 179 | z.object({ |
| 180 | type: z.literal('message_delta'), |
| 181 | delta: z.object({ |
| 182 | stop_reason: z.string().nullable().optional(), |
| 183 | stop_sequence: z.string().nullable().optional(), |
| 184 | }).optional(), |
| 185 | usage: z.object({ |
| 186 | cache_creation_input_tokens: z.number().nullable().optional(), |
| 187 | cache_read_input_tokens: z.number().nullable().optional(), |
| 188 | input_tokens: z.number().nullable().optional(), |
| 189 | output_tokens: z.number().optional(), |
| 190 | server_tool_use: z.object({ |
| 191 | web_search_requests: z.number(), |
| 192 | }).nullable().optional(), |
| 193 | }).loose().optional(), |
| 194 | }), |
| 195 | z.object({ |
| 196 | type: z.literal('message_stop'), |
| 197 | }), |
| 198 | z.object({ |
| 199 | type: z.literal('content_block_start'), |
| 200 | index: z.number(), |
| 201 | content_block: z.unknown(), |
| 202 | }), |
| 203 | z.object({ |
| 204 | type: z.literal('content_block_delta'), |
| 205 | index: z.number(), |
| 206 | delta: z.unknown(), |
| 207 | }), |
| 208 | z.object({ |
| 209 | type: z.literal('content_block_stop'), |
| 210 | index: z.number(), |
| 211 | }), |
| 212 | ]) |
| 213 | |
| 214 | const SDKUserMessageSchema = z.object({ |
| 215 | type: z.literal(AgentMessageType.User), |
| 216 | uuid: z.string().optional(), |
| 217 | message: APIUserMessageSchema.optional(), |
| 218 | content: z.union([z.string(), z.array(z.unknown())]).optional(), |
| 219 | parent_tool_use_id: z.string().nullable().optional(), |
| 220 | isSynthetic: z.boolean().optional(), |
| 221 | tool_use_result: z.unknown().optional(), |
| 222 | isReplay: z.literal(true).optional(), |
| 223 | }) |
| 224 | |
| 225 | const SDKAssistantMessageSchema = z.object({ |
| 226 | type: z.literal(AgentMessageType.Assistant), |
| 227 | uuid: z.string(), |
| 228 | message: APIAssistantMessageSchema.optional(), |
| 229 | parent_tool_use_id: z.string().nullable().optional(), |
| 230 | error: z.enum(['authentication_failed', 'billing_error', 'rate_limit', 'invalid_request', 'server_error', 'unknown']).optional(), |
| 231 | }) |
| 232 | |
| 233 | const SDKResultMessageSuccessSchema = z.object({ |
| 234 | type: z.literal(AgentMessageType.Result), |
| 235 | subtype: z.literal('success'), |
| 236 | uuid: z.string(), |
| 237 | duration_ms: z.number().optional(), |
| 238 | duration_api_ms: z.number().optional(), |
| 239 | is_error: z.boolean().optional(), |
| 240 | num_turns: z.number().optional(), |
| 241 | message: z.string().optional(), |
| 242 | result: ContentGenerationTaskResultUnionSchema.nullable().optional(), |
| 243 | total_cost_usd: z.number().optional(), |
| 244 | usage: NonNullableUsageSchema.optional(), |
| 245 | permission_denials: z.array(z.object({ |
| 246 | tool_name: z.string(), |
| 247 | tool_use_id: z.string(), |
| 248 | tool_input: z.record(z.string(), z.unknown()), |
| 249 | })).optional(), |
| 250 | structured_output: z.unknown().optional(), |
| 251 | }) |
| 252 | |
| 253 | const SDKResultMessageErrorSchema = z.object({ |
| 254 | type: z.literal(AgentMessageType.Result), |
| 255 | subtype: z.enum(['error_during_execution', 'error_max_turns', 'error_max_budget_usd', 'error_max_structured_output_retries']), |
| 256 | uuid: z.string(), |
| 257 | duration_ms: z.number().optional(), |
| 258 | duration_api_ms: z.number().optional(), |
| 259 | is_error: z.boolean().optional(), |
| 260 | num_turns: z.number().optional(), |
| 261 | total_cost_usd: z.number().optional(), |
| 262 | usage: NonNullableUsageSchema.optional(), |
| 263 | permission_denials: z.array(z.object({ |
| 264 | tool_name: z.string(), |
| 265 | tool_use_id: z.string(), |
| 266 | tool_input: z.record(z.string(), z.unknown()), |
| 267 | })).optional(), |
| 268 | errors: z.array(z.string()).optional(), |
| 269 | }) |
| 270 | |
| 271 | const SDKResultMessageSchema = z.discriminatedUnion('subtype', [ |
| 272 | SDKResultMessageSuccessSchema, |
| 273 | SDKResultMessageErrorSchema, |
| 274 | ]) |
| 275 | |
| 276 | const SDKCompactBoundaryMessageSchema = z.object({ |
| 277 | type: z.literal(AgentMessageType.System), |
| 278 | subtype: z.literal('compact_boundary'), |
| 279 | uuid: z.string(), |
| 280 | compact_metadata: z.object({ |
| 281 | trigger: z.enum(['manual', 'auto']), |
| 282 | pre_tokens: z.number(), |
| 283 | }).optional(), |
| 284 | }) |
| 285 | |
| 286 | const SDKStatusMessageSchema = z.object({ |
| 287 | type: z.literal(AgentMessageType.System), |
| 288 | subtype: z.literal('status'), |
| 289 | uuid: z.string(), |
| 290 | status: z.enum(['compacting']).nullable().optional(), |
| 291 | }) |
| 292 | |
| 293 | const SDKHookResponseMessageSchema = z.object({ |
| 294 | type: z.literal(AgentMessageType.System), |
| 295 | subtype: z.literal('hook_response'), |
| 296 | uuid: z.string(), |
| 297 | hook_name: z.string().optional(), |
| 298 | hook_event: z.string().optional(), |
| 299 | stdout: z.string().optional(), |
| 300 | stderr: z.string().optional(), |
| 301 | exit_code: z.number().optional(), |
| 302 | }) |
| 303 | |
| 304 | const SDKSystemMessageSchema = z.discriminatedUnion('subtype', [ |
| 305 | SDKCompactBoundaryMessageSchema, |
| 306 | SDKStatusMessageSchema, |
| 307 | SDKHookResponseMessageSchema, |
| 308 | ]) |
| 309 | |
| 310 | const SDKPartialAssistantMessageSchema = z.object({ |
| 311 | type: z.literal(AgentMessageType.StreamEvent), |
| 312 | uuid: z.string(), |
| 313 | event: RawMessageStreamEventSchema.optional(), |
| 314 | parent_tool_use_id: z.string().nullable().optional(), |
| 315 | }) |
| 316 | |
| 317 | const SDKToolProgressMessageSchema = z.object({ |
| 318 | type: z.literal(AgentMessageType.ToolProgress), |
| 319 | uuid: z.string(), |
| 320 | tool_use_id: z.string().optional(), |
| 321 | tool_name: z.string().optional(), |
| 322 | parent_tool_use_id: z.string().nullable().optional(), |
| 323 | elapsed_time_seconds: z.number().optional(), |
| 324 | }) |
| 325 | |
| 326 | const SDKAuthStatusMessageSchema = z.object({ |
| 327 | type: z.literal(AgentMessageType.AuthStatus), |
| 328 | uuid: z.string(), |
| 329 | isAuthenticating: z.boolean().optional(), |
| 330 | output: z.array(z.string()).optional(), |
| 331 | error: z.string().optional(), |
| 332 | }) |
| 333 | |
| 334 | const SDKErrorMessageSchema = z.object({ |
| 335 | type: z.literal(AgentMessageType.Error), |
| 336 | code: z.number(), |
| 337 | message: z.string(), |
| 338 | data: z.unknown().optional(), |
| 339 | timestamp: z.number(), |
| 340 | }) |
| 341 | |
| 342 | export const AgentMessageVoSchema = z.discriminatedUnion('type', [ |
| 343 | SDKUserMessageSchema, |
| 344 | SDKAssistantMessageSchema, |
| 345 | SDKResultMessageSchema, |
| 346 | SDKSystemMessageSchema, |
| 347 | SDKPartialAssistantMessageSchema, |
| 348 | SDKToolProgressMessageSchema, |
| 349 | SDKAuthStatusMessageSchema, |
| 350 | SDKErrorMessageSchema, |
| 351 | ]) |
| 352 | |
| 353 | export type AgentMessageVo = z.infer<typeof AgentMessageVoSchema> |
| 354 | |
| 355 | export const AgentMessageVoHelper = { |
| 356 | create: (input: unknown): AgentMessageVo => { |
| 357 | return AgentMessageVoSchema.parse(input) |
| 358 | }, |
| 359 | } |
| 360 | |
| 361 | export const ContentGenerationTaskVoSchema = z.object({ |
| 362 | id: z.string(), |
| 363 | userId: z.string(), |
| 364 | createdAt: z.coerce.date(), |
| 365 | updatedAt: z.coerce.date(), |
| 366 | title: z.string().optional(), |
| 367 | messages: z.array(AgentMessageVoSchema).optional(), |
| 368 | status: z.enum(ContentGenerationTaskStatus), |
| 369 | rating: z.number().int().min(1).max(5).optional(), |
| 370 | ratingComment: z.string().optional(), |
| 371 | favoritedAt: z.coerce.date().nullable().optional(), |
| 372 | }) |
| 373 | export class ContentGenerationTaskVo extends createZodDto(ContentGenerationTaskVoSchema) { } |
| 374 | |
| 375 | export const ContentGenerationTaskListItemVoSchema = z.object({ |
| 376 | id: z.string(), |
| 377 | userId: z.string(), |
| 378 | title: z.string().optional(), |
| 379 | status: z.enum(ContentGenerationTaskStatus), |
| 380 | createdAt: z.coerce.date(), |
| 381 | updatedAt: z.coerce.date(), |
| 382 | rating: z.number().int().min(1).max(5).optional(), |
| 383 | ratingComment: z.string().optional(), |
| 384 | favoritedAt: z.coerce.date().nullable().optional(), |
| 385 | }) |
| 386 | export class ContentGenerationTaskListItemVo extends createZodDto(ContentGenerationTaskListItemVoSchema) { } |
| 387 | |
| 388 | export class ContentGenerationTaskListVo extends createPaginationVo(ContentGenerationTaskListItemVoSchema, 'ContentGenerationTaskListVo') { } |
| 389 | |
| 390 | export const ContentGenerationTaskInitChunkVoSchema = z.object({ |
| 391 | type: z.literal(AgentMessageType.Init), |
| 392 | taskId: z.string(), |
| 393 | messages: z.array(AgentMessageVoSchema).optional(), |
| 394 | }) |
| 395 | export class ContentGenerationTaskInitChunkVo extends createZodDto(ContentGenerationTaskInitChunkVoSchema) { } |
| 396 | |
| 397 | export const ContentGenerationTaskKeepAliveChunkVoSchema = z.object({ |
| 398 | type: z.literal(AgentMessageType.KeepAlive), |
| 399 | }) |
| 400 | export class ContentGenerationTaskKeepAliveChunkVo extends createZodDto(ContentGenerationTaskKeepAliveChunkVoSchema) { } |
| 401 | |
| 402 | export const ContentGenerationTaskTitleUpdatedChunkVoSchema = z.object({ |
| 403 | type: z.literal(AgentMessageType.TitleUpdated), |
| 404 | taskId: z.string(), |
| 405 | title: z.string(), |
| 406 | }) |
| 407 | export class ContentGenerationTaskTitleUpdatedChunkVo extends createZodDto(ContentGenerationTaskTitleUpdatedChunkVoSchema) { } |
| 408 | |
| 409 | export const ContentGenerationTaskErrorChunkVoSchema = z.object({ |
| 410 | type: z.literal(AgentMessageType.Error), |
| 411 | code: z.number(), |
| 412 | message: z.string(), |
| 413 | data: z.unknown().optional(), |
| 414 | timestamp: z.number(), |
| 415 | }) |
| 416 | export class ContentGenerationTaskErrorChunkVo extends createZodDto(ContentGenerationTaskErrorChunkVoSchema) { } |
| 417 | |
| 418 | export const ContentGenerationTaskAgentChunkVoSchema = z.object({ |
| 419 | type: z.enum([ |
| 420 | AgentMessageType.Assistant, |
| 421 | AgentMessageType.User, |
| 422 | AgentMessageType.Result, |
| 423 | AgentMessageType.System, |
| 424 | AgentMessageType.StreamEvent, |
| 425 | AgentMessageType.ToolProgress, |
| 426 | AgentMessageType.AuthStatus, |
| 427 | ]), |
| 428 | message: AgentMessageVoSchema, |
| 429 | }) |
| 430 | export class ContentGenerationTaskAgentChunkVo extends createZodDto(ContentGenerationTaskAgentChunkVoSchema) { } |
| 431 | |
| 432 | export type ContentGenerationTaskChunkVo |
| 433 | = | ContentGenerationTaskInitChunkVo |
| 434 | | ContentGenerationTaskKeepAliveChunkVo |
| 435 | | ContentGenerationTaskTitleUpdatedChunkVo |
| 436 | | ContentGenerationTaskAgentChunkVo |
| 437 | | ContentGenerationTaskErrorChunkVo |
| 438 | |
| 439 | export const ContentGenerationTaskChunkVoSchema = z.discriminatedUnion('type', [ |
| 440 | ContentGenerationTaskInitChunkVoSchema, |
| 441 | ContentGenerationTaskKeepAliveChunkVoSchema, |
| 442 | ContentGenerationTaskTitleUpdatedChunkVoSchema, |
| 443 | ContentGenerationTaskAgentChunkVoSchema, |
| 444 | ContentGenerationTaskErrorChunkVoSchema, |
| 445 | ]) |
| 446 | |
| 447 | export const TaskMessagesVoSchema = z.object({ |
| 448 | messages: z.array(AgentMessageVoSchema), |
| 449 | status: z.enum(ContentGenerationTaskStatus), |
| 450 | }) |
| 451 | export class TaskMessagesVo extends createZodDto(TaskMessagesVoSchema, 'TaskMessagesVo') { } |
| 452 | |
| 453 | export const PublicShareVoSchema = z.object({ |
| 454 | token: z.string(), |
| 455 | expiresAt: z.coerce.date(), |
| 456 | }) |
| 457 | export class PublicShareVo extends createZodDto(PublicShareVoSchema, 'PublicShareVo') { } |
| 458 |