Files
arc53--docsgpt/application/alembic/versions/0018_tool_attempts_attribution.py
wehub-resource-sync fed8b2eed7
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Backend release / release (push) Has been cancelled
Bandit Security Scan / bandit_scan (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / manifest (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / manifest (push) Has been cancelled
Python linting / ruff (push) Has been cancelled
Run python tests with pytest / Run tests and count coverage (3.12) (push) Has been cancelled
React Widget Build / build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:28:29 +08:00

57 lines
2.3 KiB
Python

"""0018 tool_call_attempts attribution — record user/agent on the journal.
Adds ``tool_call_attempts.user_id`` / ``agent_id`` so tool analytics can
attribute attempts that never get a ``message_id`` — headless runs
(scheduled / webhook) execute tools before any conversation message
exists, and parse-failure rows never reach one at all.
DDL only — a whole-table UPDATE here would hold the ALTERs' ACCESS
EXCLUSIVE lock across the rewrite and stall live tool journaling. The
backfill lives in ``scripts/db/backfill_tool_attempts_attribution.py``;
until it runs, the analytics reader falls back to the parent message's
user for unstamped rows.
The index is built ``CONCURRENTLY`` in an autocommit block: the
``ADD COLUMN`` ALTERs commit first (a fast metadata-only change), so the
O(table-size) index build never runs while their ACCESS EXCLUSIVE lock
is held and never blocks live journaling.
Revision ID: 0018_tool_attempts_attribution
Revises: 0017_oidc_scim
"""
from typing import Sequence, Union
from alembic import op
revision: str = "0018_tool_attempts_attribution"
down_revision: Union[str, None] = "0017_oidc_scim"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.execute("ALTER TABLE tool_call_attempts ADD COLUMN user_id TEXT;")
op.execute("ALTER TABLE tool_call_attempts ADD COLUMN agent_id UUID;")
# CONCURRENTLY can't run inside a transaction; the autocommit block
# commits the ALTERs above (releasing their lock) before building.
# DROP IF EXISTS first so a failed concurrent build (which leaves an
# INVALID index) is cleaned up on re-run.
with op.get_context().autocommit_block():
op.execute("DROP INDEX IF EXISTS tool_call_attempts_user_ts_idx;")
op.execute(
"CREATE INDEX CONCURRENTLY tool_call_attempts_user_ts_idx "
"ON tool_call_attempts (user_id, attempted_at DESC) "
"WHERE user_id IS NOT NULL;"
)
def downgrade() -> None:
with op.get_context().autocommit_block():
op.execute(
"DROP INDEX CONCURRENTLY IF EXISTS tool_call_attempts_user_ts_idx;"
)
op.execute("ALTER TABLE tool_call_attempts DROP COLUMN IF EXISTS agent_id;")
op.execute("ALTER TABLE tool_call_attempts DROP COLUMN IF EXISTS user_id;")