d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
82 lines
2.6 KiB
TypeScript
82 lines
2.6 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
/**
|
|
* One-shot reconciliation: copy any messages present in
|
|
* `copilot_chats.messages` JSONB but missing from `copilot_messages`.
|
|
*
|
|
* Idempotent via `ON CONFLICT (chat_id, message_id) DO NOTHING`. Safe to
|
|
* re-run. Intended to be run manually before cutting reads over to the new
|
|
* table (R+1 of the dual-write rollout), or after a known dual-write outage.
|
|
*
|
|
* Usage:
|
|
* DATABASE_URL=... bun apps/sim/scripts/copilot-messages-reconcile.ts [--since=<interval>]
|
|
*
|
|
* Examples:
|
|
* bun apps/sim/scripts/copilot-messages-reconcile.ts
|
|
* bun apps/sim/scripts/copilot-messages-reconcile.ts --since='7 days'
|
|
* bun apps/sim/scripts/copilot-messages-reconcile.ts --since='1 hour'
|
|
*
|
|
* Omit --since to reconcile the entire table.
|
|
*/
|
|
|
|
import { sql } from 'drizzle-orm'
|
|
import { db } from '../../../packages/db/db.js'
|
|
|
|
function parseSinceArg(argv: string[]): string | null {
|
|
const arg = argv.find((a) => a.startsWith('--since='))
|
|
if (!arg) return null
|
|
const value = arg.slice('--since='.length).trim()
|
|
if (!value) {
|
|
throw new Error('--since requires a value, e.g. --since="7 days"')
|
|
}
|
|
if (!/^[\w\s]+$/.test(value)) {
|
|
throw new Error(`--since value must be a simple interval like "7 days"; got: ${value}`)
|
|
}
|
|
return value
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const since = parseSinceArg(process.argv.slice(2))
|
|
const windowClause = since
|
|
? sql`AND c.updated_at > now() - ${sql.raw(`interval '${since}'`)}`
|
|
: sql``
|
|
|
|
console.log(
|
|
since
|
|
? `Reconciling copilot_messages for chats updated in the last ${since}…`
|
|
: 'Reconciling copilot_messages across the full copilot_chats table…'
|
|
)
|
|
const startedAt = Date.now()
|
|
|
|
const result = await db.execute(sql`
|
|
INSERT INTO copilot_messages (chat_id, message_id, role, content, model, created_at, updated_at)
|
|
SELECT
|
|
c.id,
|
|
msg.value->>'id',
|
|
msg.value->>'role',
|
|
msg.value,
|
|
c.model,
|
|
(msg.value->>'timestamp')::timestamptz,
|
|
(msg.value->>'timestamp')::timestamptz
|
|
FROM copilot_chats c
|
|
CROSS JOIN LATERAL jsonb_array_elements(c.messages) AS msg(value)
|
|
WHERE jsonb_typeof(c.messages) = 'array'
|
|
AND jsonb_array_length(c.messages) > 0
|
|
${windowClause}
|
|
ON CONFLICT (chat_id, message_id) DO NOTHING
|
|
`)
|
|
|
|
const elapsedMs = Date.now() - startedAt
|
|
const rowCount = (result as { rowCount?: number }).rowCount ?? 0
|
|
console.log(`Inserted ${rowCount} new rows in ${(elapsedMs / 1000).toFixed(1)}s.`)
|
|
}
|
|
|
|
main()
|
|
.catch((err) => {
|
|
console.error('Reconciliation failed:', err)
|
|
process.exit(1)
|
|
})
|
|
.finally(() => {
|
|
process.exit(0)
|
|
})
|