| @@ -73,6 +73,13 @@ import { · 72 unmodified lines |
| 73 | upsertDocument as upsertDocumentEffect, | 73 | upsertDocument as upsertDocumentEffect, |
| 74 | type DocumentRow, | 74 | type DocumentRow, |
| 75 | } from "./persistence/documentsRepo"; | 75 | } from "./persistence/documentsRepo"; |
| | 76 | import { |
| | 77 | insertProviderEvent as insertProviderEventEffect, |
| | 78 | listCompletedItemEventsBySessionTurn as listCompletedItemEventsBySessionTurnEffect, |
| | 79 | listCompletedItemEventsByThreadTurn as listCompletedItemEventsByThreadTurnEffect, |
| | 80 | listCompletedItemEventsByTurn as listCompletedItemEventsByTurnEffect, |
| | 81 | type CompletedProviderItemRow, |
| | 82 | } from "./persistence/providerEventsRepo"; |
| 76 | import { | 83 | import { |
| 77 | appendStateEvent as appendStateEventEffect, | 84 | appendStateEvent as appendStateEventEffect, |
| 78 | listStateEventsAfterSeq as listStateEventsAfterSeqEffect, | 85 | listStateEventsAfterSeq as listStateEventsAfterSeqEffect, |
| @@ -1570,38 +1577,55 @@ export class PersistenceService extends EventEmitter<PersistenceServiceEvents> { · 1491 unmodified lines |
| 1570 | sessionId?: string; | 1577 | sessionId?: string; |
| 1571 | runtimeThreadId?: string | null; | 1578 | runtimeThreadId?: string | null; |
| 1572 | }): string | undefined { | 1579 | }): string | undefined { |
| 1573 | const queries: Array<{ sql: string; params: unknown[] }> = []; | 1580 | const rowGroups: CompletedProviderItemRow[][] = []; |
| 1574 | if (input.sessionId) { | 1581 | if (input.sessionId) { |
| 1575 | queries.push({ | 1582 | rowGroups.push( |
| 1576 | sql: `SELECT item_id, payload_json | 1583 | this.runWithEffectSql( |
| 1577 | FROM provider_events | 1584 | listCompletedItemEventsBySessionTurnEffect({ |
| 1578 | WHERE session_id = ? AND turn_id = ? AND method = 'item/completed' | 1585 | sessionId: input.sessionId, |
| 1579 | ORDER BY created_at DESC;`, | 1586 | turnId: input.turnId, |
| 1580 | params: [input.sessionId, input.turnId], | 1587 | }), |
| 1581 | }); | 1588 | () => |
| | 1589 | this.db.prepare( |
| | 1590 | `SELECT item_id, payload_json |
| | 1591 | FROM provider_events |
| | 1592 | WHERE session_id = ? AND turn_id = ? AND method = 'item/completed' |
| | 1593 | ORDER BY created_at DESC;`, |
| | 1594 | ).all(input.sessionId, input.turnId) as CompletedProviderItemRow[], |
| | 1595 | ), |
| | 1596 | ); |
| 1582 | } | 1597 | } |
| 1583 | if (input.runtimeThreadId) { | 1598 | if (input.runtimeThreadId) { |
| 1584 | queries.push({ | 1599 | rowGroups.push( |
| 1585 | sql: `SELECT item_id, payload_json | 1600 | this.runWithEffectSql( |
| 1586 | FROM provider_events | 1601 | listCompletedItemEventsByThreadTurnEffect({ |
| 1587 | WHERE thread_id = ? AND turn_id = ? AND method = 'item/completed' | 1602 | runtimeThreadId: input.runtimeThreadId, |
| 1588 | ORDER BY created_at DESC;`, | 1603 | turnId: input.turnId, |
| 1589 | params: [input.runtimeThreadId, input.turnId], | 1604 | }), |
| 1590 | }); | 1605 | () => |
| | 1606 | this.db.prepare( |
| | 1607 | `SELECT item_id, payload_json |
| | 1608 | FROM provider_events |
| | 1609 | WHERE thread_id = ? AND turn_id = ? AND method = 'item/completed' |
| | 1610 | ORDER BY created_at DESC;`, |
| | 1611 | ).all(input.runtimeThreadId, input.turnId) as CompletedProviderItemRow[], |
| | 1612 | ), |
| | 1613 | ); |
| 1591 | } | 1614 | } |
| 1592 | queries.push({ | 1615 | rowGroups.push( |
| 1593 | sql: `SELECT item_id, payload_json | 1616 | this.runWithEffectSql( |
| 1594 | FROM provider_events | 1617 | listCompletedItemEventsByTurnEffect(input.turnId), |
| 1595 | WHERE turn_id = ? AND method = 'item/completed' | 1618 | () => |
| 1596 | ORDER BY created_at DESC;`, | 1619 | this.db.prepare( |
| 1597 | params: [input.turnId], | 1620 | `SELECT item_id, payload_json |
| 1598 | }); | 1621 | FROM provider_events |
| | 1622 | WHERE turn_id = ? AND method = 'item/completed' |
| | 1623 | ORDER BY created_at DESC;`, |
| | 1624 | ).all(input.turnId) as CompletedProviderItemRow[], |
| | 1625 | ), |
| | 1626 | ); |
| 1599 | | 1627 | |
| 1600 | for (const query of queries) { | 1628 | for (const rows of rowGroups) { |
| 1601 | const rows = this.db.prepare(query.sql).all(...query.params) as Array<{ | | |
| 1602 | item_id: string | null; | | |
| 1603 | payload_json: string | null; | | |
| 1604 | }>; | | |
| 1605 | for (const row of rows) { | 1629 | for (const row of rows) { |
| 1606 | const payload = row.payload_json ? this.tryParseJson(row.payload_json) : null; | 1630 | const payload = row.payload_json ? this.tryParseJson(row.payload_json) : null; |
| 1607 | const item = asObject(asObject(payload)?.item); | 1631 | const item = asObject(asObject(payload)?.item); |
| @@ -1774,43 +1798,64 @@ export class PersistenceService extends EventEmitter<PersistenceServiceEvents> { · 166 unmodified lines |
| 1774 | private insertProviderEvent(event: ProviderEvent): ProviderEventInsertResult { | 1798 | private insertProviderEvent(event: ProviderEvent): ProviderEventInsertResult { |
| 1775 | const runtimeThreadId = event.threadId ?? parseThreadIdFromEventPayload(event.payload); | 1799 | const runtimeThreadId = event.threadId ?? parseThreadIdFromEventPayload(event.payload); |
| 1776 | const payloadJson = event.payload === undefined ? null : JSON.stringify(event.payload); | 1800 | const payloadJson = event.payload === undefined ? null : JSON.stringify(event.payload); |
| 1777 | const result = this.db | 1801 | const changes = this.runWithEffectSql( |
| 1778 | .prepare( | 1802 | insertProviderEventEffect({ |
| 1779 | `INSERT OR IGNORE INTO provider_events ( | 1803 | id: event.id, |
| 1780 | id, | 1804 | sessionId: event.sessionId, |
| 1781 | session_id, | 1805 | provider: event.provider, |
| 1782 | provider, | 1806 | kind: event.kind, |
| 1783 | kind, | 1807 | method: event.method, |
| 1784 | method, | 1808 | runtimeThreadId: runtimeThreadId ?? null, |
| 1785 | thread_id, | 1809 | turnId: event.turnId ?? null, |
| 1786 | turn_id, | 1810 | itemId: event.itemId ?? null, |
| 1787 | item_id, | 1811 | requestId: event.requestId ?? null, |
| 1788 | request_id, | 1812 | requestKind: event.requestKind ?? null, |
| 1789 | request_kind, | 1813 | textDelta: event.textDelta ?? null, |
| 1790 | text_delta, | 1814 | message: event.message ?? null, |
| 1791 | message, | | |
| 1792 | payload_json, | | |
| 1793 | created_at | | |
| 1794 | ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`, | | |
| 1795 | ) | | |
| 1796 | .run( | | |
| 1797 | event.id, | | |
| 1798 | event.sessionId, | | |
| 1799 | event.provider, | | |
| 1800 | event.kind, | | |
| 1801 | event.method, | | |
| 1802 | runtimeThreadId, | | |
| 1803 | event.turnId ?? null, | | |
| 1804 | event.itemId ?? null, | | |
| 1805 | event.requestId ?? null, | | |
| 1806 | event.requestKind ?? null, | | |
| 1807 | event.textDelta ?? null, | | |
| 1808 | event.message ?? null, | | |
| 1809 | payloadJson, | 1815 | payloadJson, |
| 1810 | event.createdAt, | 1816 | createdAt: event.createdAt, |
| 1811 | ) as { changes?: number | bigint }; | 1817 | }), |
| | 1818 | () => { |
| | 1819 | const result = this.db |
| | 1820 | .prepare( |
| | 1821 | `INSERT OR IGNORE INTO provider_events ( |
| | 1822 | id, |
| | 1823 | session_id, |
| | 1824 | provider, |
| | 1825 | kind, |
| | 1826 | method, |
| | 1827 | thread_id, |
| | 1828 | turn_id, |
| | 1829 | item_id, |
| | 1830 | request_id, |
| | 1831 | request_kind, |
| | 1832 | text_delta, |
| | 1833 | message, |
| | 1834 | payload_json, |
| | 1835 | created_at |
| | 1836 | ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`, |
| | 1837 | ) |
| | 1838 | .run( |
| | 1839 | event.id, |
| | 1840 | event.sessionId, |
| | 1841 | event.provider, |
| | 1842 | event.kind, |
| | 1843 | event.method, |
| | 1844 | runtimeThreadId, |
| | 1845 | event.turnId ?? null, |
| | 1846 | event.itemId ?? null, |
| | 1847 | event.requestId ?? null, |
| | 1848 | event.requestKind ?? null, |
| | 1849 | event.textDelta ?? null, |
| | 1850 | event.message ?? null, |
| | 1851 | payloadJson, |
| | 1852 | event.createdAt, |
| | 1853 | ) as { changes?: number | bigint }; |
| | 1854 | return toSafeInteger(result.changes, 0); |
| | 1855 | }, |
| | 1856 | ); |
| 1812 | return { | 1857 | return { |
| 1813 | inserted: toSafeInteger(result.changes, 0) > 0, | 1858 | inserted: changes > 0, |
| 1814 | runtimeThreadId: runtimeThreadId ?? null, | 1859 | runtimeThreadId: runtimeThreadId ?? null, |
| 1815 | }; | 1860 | }; |
| 1816 | } | 1861 | } |