"""tighten agent runtime latency budgets Revision ID: 20260516_agent_fast_latency_budget Revises: 20260516_agent_objective_contract_fast_path Create Date: 2026-05-16 """ from __future__ import annotations import json import os from typing import Any from alembic import op import sqlalchemy as sa revision = "20260516_agent_fast_latency_budget" down_revision = "20260516_agent_objective_contract_fast_path" branch_labels = None depends_on = None REFRESH_NOTES = "Refreshed by 20260516_agent_fast_latency_budget" PROMPT_KEYS = ( "PROMPT_PMFLOW_AI_AGENT_GOAL_FRAME", "PROMPT_PMFLOW_AI_AGENT_STEP_PLANNER", "PROMPT_PMFLOW_AI_AGENT_EVIDENCE_NORMALIZER", "PROMPT_PMFLOW_AI_AGENT_STATE_CRITIC", "PROMPT_PMFLOW_AI_AGENT_ANSWER_COMPOSER", "PROMPT_PMFLOW_AI_AGENT_ANSWER_REVISER", ) def _table_exists(bind: Any, table_name: str) -> bool: return sa.inspect(bind).has_table(table_name) def _refresh_runtime_profiles(bind: Any, *, tenant_id: int) -> None: if not _table_exists(bind, "integrations"): return row = bind.execute( sa.text( """ SELECT id, config FROM integrations WHERE tenant_id = :tenant_id AND type = 'ai_function_runtime_profiles' AND is_active = true ORDER BY id DESC LIMIT 1 """ ), {"tenant_id": tenant_id}, ).mappings().first() if row is None: return config = row.get("config") if isinstance(row.get("config"), dict) else {} changed = False caps = { "pmflow_ai_agent_goal_frame": (12, 14), "pmflow_ai_agent_step_planner": (8, 10), "pmflow_ai_agent_evidence_normalizer": (12, 14), "pmflow_ai_agent_state_critic": (8, 10), "pmflow_ai_agent_answer_composer": (14, 16), "pmflow_ai_agent_answer_reviser": (10, 12), } for stage in ("active", "draft"): profiles = ((config.get(stage) or {}).get("profiles") or {}) if isinstance(config.get(stage), dict) else {} for key, (provider_timeout, job_timeout) in caps.items(): profile = profiles.get(key) if not isinstance(profile, dict): continue if int(profile.get("provider_timeout_seconds") or 0) > provider_timeout: profile["provider_timeout_seconds"] = provider_timeout changed = True if int(profile.get("job_timeout_seconds") or 0) > job_timeout: profile["job_timeout_seconds"] = job_timeout changed = True if profile.get("response_mode") != "fast": profile["response_mode"] = "fast" changed = True if not changed: return config["active_version"] = "profile-v20260516-agent-fast-latency-budget" config["version"] = config["active_version"] bind.execute( sa.text("UPDATE integrations SET config = CAST(:config AS jsonb) WHERE id = :id"), {"id": int(row["id"]), "config": json.dumps(config, ensure_ascii=False)}, ) def _prompt_body(prompt_key: str) -> str: from app.config import ai_prompts return str(getattr(ai_prompts, prompt_key, "") or "").strip() def _refresh_active_prompt(bind: Any, *, tenant_id: int, prompt_key: str, body_snapshot: str) -> None: if not _table_exists(bind, "prompt_releases"): return active = bind.execute( sa.text( """ SELECT id, body_snapshot FROM prompt_releases WHERE tenant_id = :tenant_id AND prompt_key = :prompt_key AND status = 'active' LIMIT 1 """ ), {"tenant_id": tenant_id, "prompt_key": prompt_key}, ).mappings().first() if active is not None and str(active.get("body_snapshot") or "").strip() == body_snapshot: return bind.execute( sa.text( """ UPDATE prompt_releases SET status = 'archived' WHERE tenant_id = :tenant_id AND prompt_key = :prompt_key AND status = 'active' """ ), {"tenant_id": tenant_id, "prompt_key": prompt_key}, ) max_version = bind.execute( sa.text( """ SELECT MAX(version) FROM prompt_releases WHERE tenant_id = :tenant_id AND prompt_key = :prompt_key """ ), {"tenant_id": tenant_id, "prompt_key": prompt_key}, ).scalar() bind.execute( sa.text( """ INSERT INTO prompt_releases (tenant_id, prompt_key, version, body_snapshot, status, notes, created_by, activated_by, activated_at) VALUES (:tenant_id, :prompt_key, :version, :body_snapshot, 'active', :notes, NULL, NULL, :activated_at) """ ), { "tenant_id": tenant_id, "prompt_key": prompt_key, "version": int(max_version or 0) + 1, "body_snapshot": body_snapshot, "notes": REFRESH_NOTES, "activated_at": "2026-05-16T00:00:00", }, ) def upgrade() -> None: tenant_id = int(os.getenv("PMFLOW_PLATFORM_RUNTIME_TENANT_ID", "1") or "1") bind = op.get_bind() for prompt_key in PROMPT_KEYS: body = _prompt_body(prompt_key) if body: _refresh_active_prompt(bind, tenant_id=tenant_id, prompt_key=prompt_key, body_snapshot=body) _refresh_runtime_profiles(bind, tenant_id=tenant_id) def downgrade() -> None: return None