148 lines · 4.2 KB · TypeScript
RawDownload
import * as SqlClient from "effect/unstable/sql/SqlClient";import * as Effect from "effect/Effect"; export default Effect.gen(function* () {  const sql = yield* SqlClient.SqlClient;   yield* sql`    ALTER TABLE projection_thread_activities    ADD COLUMN user_input_request_id TEXT  `;   yield* sql`    ALTER TABLE projection_thread_activities    ADD COLUMN user_input_state TEXT    CHECK (user_input_state IN ('pending', 'cleared'))  `;   yield* sql`    UPDATE projection_thread_activities    SET      user_input_request_id = CASE        WHEN json_valid(payload_json) THEN CASE          WHEN json_type(payload_json, '$.requestId') = 'text'            THEN json_extract(payload_json, '$.requestId')          ELSE NULL        END        ELSE NULL      END,      user_input_state = CASE        WHEN kind = 'user-input.requested' THEN 'pending'        WHEN kind = 'user-input.resolved' THEN 'cleared'        WHEN kind = 'provider.user-input.respond.failed'          AND json_valid(payload_json)          AND json_type(payload_json, '$.detail') = 'text'          THEN CASE            WHEN lower(json_extract(payload_json, '$.detail'))              LIKE '%stale pending user-input request%'              OR lower(json_extract(payload_json, '$.detail'))                LIKE '%unknown pending user-input request%'              OR lower(json_extract(payload_json, '$.detail'))                LIKE '%unknown pending user input request%'              OR lower(json_extract(payload_json, '$.detail'))                LIKE '%unknown pending codex user input request%'              THEN 'cleared'            ELSE NULL          END        ELSE NULL      END    WHERE kind IN (      'user-input.requested',      'user-input.resolved',      'provider.user-input.respond.failed'    )  `;   yield* sql`    UPDATE projection_thread_activities    SET user_input_state = NULL    WHERE user_input_request_id IS NULL  `;   yield* sql`    UPDATE projection_thread_activities    SET user_input_request_id = NULL    WHERE user_input_state IS NULL  `;   yield* sql`    CREATE INDEX IF NOT EXISTS idx_projection_thread_activities_user_input_state    ON projection_thread_activities(      thread_id,      user_input_request_id,      created_at DESC,      activity_id DESC    )    WHERE user_input_state IS NOT NULL  `;   yield* sql`    DROP INDEX IF EXISTS idx_projection_thread_activities_thread_user_input_lifecycle  `;   yield* sql`    CREATE TABLE IF NOT EXISTS projection_thread_user_input_summaries (      thread_id TEXT PRIMARY KEY,      pending_count INTEGER NOT NULL CHECK (pending_count >= 0)    )  `;   yield* sql`    WITH ranked AS (      SELECT        thread_id,        user_input_request_id,        user_input_state,        ROW_NUMBER() OVER (          PARTITION BY thread_id, user_input_request_id          ORDER BY created_at DESC, activity_id DESC        ) AS row_number      FROM projection_thread_activities      WHERE user_input_state IS NOT NULL        AND user_input_request_id IS NOT NULL    )    INSERT INTO projection_thread_user_input_summaries (      thread_id,      pending_count    )    SELECT      thread_id,      SUM(CASE WHEN user_input_state = 'pending' THEN 1 ELSE 0 END)    FROM ranked    WHERE row_number = 1    GROUP BY thread_id  `;   yield* sql`    INSERT OR IGNORE INTO projection_thread_user_input_summaries (      thread_id,      pending_count    )    SELECT thread_id, 0    FROM projection_threads  `;   yield* sql`    CREATE INDEX IF NOT EXISTS idx_projection_thread_messages_latest_user    ON projection_thread_messages(thread_id, created_at DESC, message_id DESC)    WHERE role = 'user'  `;   yield* sql`    UPDATE projection_threads    SET      pending_user_input_count = COALESCE((        SELECT summary.pending_count        FROM projection_thread_user_input_summaries AS summary        WHERE summary.thread_id = projection_threads.thread_id      ), 0),      latest_user_message_at = (        SELECT message.created_at        FROM projection_thread_messages AS message        WHERE message.thread_id = projection_threads.thread_id          AND message.role = 'user'        ORDER BY message.created_at DESC, message.message_id DESC        LIMIT 1      )  `;});