* Add a message to a thread * Automatically assigns sequence_number
(input: CreateMessageInput)
| 433 | * Automatically assigns sequence_number |
| 434 | */ |
| 435 | async addMessage(input: CreateMessageInput): Promise<ThreadMessage> { |
| 436 | const pool = getPool(); |
| 437 | const client = await pool.connect(); |
| 438 | |
| 439 | try { |
| 440 | await client.query('BEGIN'); |
| 441 | |
| 442 | // Get next sequence number |
| 443 | const seqResult = await client.query<{ next_seq: number }>( |
| 444 | `SELECT COALESCE(MAX(sequence_number), 0) + 1 as next_seq |
| 445 | FROM addie_thread_messages WHERE thread_id = $1`, |
| 446 | [input.thread_id] |
| 447 | ); |
| 448 | const sequenceNumber = seqResult.rows[0].next_seq; |
| 449 | |
| 450 | // Insert message with enhanced execution metadata |
| 451 | const result = await client.query<ThreadMessage>( |
| 452 | `INSERT INTO addie_thread_messages ( |
| 453 | thread_id, role, content, content_sanitized, tools_used, tool_calls, |
| 454 | knowledge_ids, model, latency_ms, tokens_input, tokens_output, |
| 455 | flagged, flag_reason, sequence_number, |
| 456 | timing_system_prompt_ms, timing_total_llm_ms, timing_total_tool_ms, |
| 457 | processing_iterations, tokens_cache_creation, tokens_cache_read, active_rule_ids, |
| 458 | router_decision, config_version_id, email_message_id, |
| 459 | user_id, user_display_name |
| 460 | ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26) |
| 461 | RETURNING *`, |
| 462 | [ |
| 463 | input.thread_id, |
| 464 | input.role, |
| 465 | stripNullBytesString(input.content), |
| 466 | input.content_sanitized != null ? stripNullBytesString(input.content_sanitized) : null, |
| 467 | input.tools_used ? input.tools_used.map(stripNullBytesString) : null, |
| 468 | input.tool_calls ? stripNullBytesFromJson(JSON.stringify(input.tool_calls)) : null, |
| 469 | input.knowledge_ids ?? null, |
| 470 | input.model ?? null, |
| 471 | input.latency_ms ?? null, |
| 472 | input.tokens_input ?? null, |
| 473 | input.tokens_output ?? null, |
| 474 | input.flagged ?? false, |
| 475 | input.flag_reason != null ? stripNullBytesString(input.flag_reason) : null, |
| 476 | sequenceNumber, |
| 477 | input.timing?.system_prompt_ms ?? null, |
| 478 | input.timing?.total_llm_ms ?? null, |
| 479 | input.timing?.total_tool_ms ?? null, |
| 480 | input.timing?.iterations ?? null, |
| 481 | input.tokens_cache_creation ?? null, |
| 482 | input.tokens_cache_read ?? null, |
| 483 | input.active_rule_ids ?? null, |
| 484 | input.router_decision ? stripNullBytesFromJson(JSON.stringify(input.router_decision)) : null, |
| 485 | input.config_version_id ?? null, |
| 486 | input.email_message_id != null ? stripNullBytesString(input.email_message_id) : null, |
| 487 | input.user_id ?? null, |
| 488 | input.user_display_name != null ? stripNullBytesString(input.user_display_name) : null, |
| 489 | ] |
| 490 | ); |
| 491 | |
| 492 | await client.query('COMMIT'); |
no test coverage detected