Bridge legacy QuoteJudge database columns
This commit is contained in:
2
a2a.yaml
2
a2a.yaml
@@ -1,5 +1,5 @@
|
|||||||
name: quote-judge-studio-v1
|
name: quote-judge-studio-v1
|
||||||
version: 0.1.4
|
version: 0.1.5
|
||||||
entrypoint: agent:QuoteJudgeStudioV1
|
entrypoint: agent:QuoteJudgeStudioV1
|
||||||
expose:
|
expose:
|
||||||
public: false
|
public: false
|
||||||
|
|||||||
19
agent.py
19
agent.py
@@ -108,7 +108,7 @@ class QuoteJudgeStudioV1(A2AAgent[QuoteJudgeStudioV1Config, PlatformUserAuth]):
|
|||||||
"QuoteJudge compares vendor quotes with weighted price, delivery, and "
|
"QuoteJudge compares vendor quotes with weighted price, delivery, and "
|
||||||
"warranty scoring, persists per-user comparisons, and serves a one-page product UI."
|
"warranty scoring, persists per-user comparisons, and serves a one-page product UI."
|
||||||
)
|
)
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
|
|
||||||
config_model = QuoteJudgeStudioV1Config
|
config_model = QuoteJudgeStudioV1Config
|
||||||
auth_model = PlatformUserAuth
|
auth_model = PlatformUserAuth
|
||||||
@@ -574,11 +574,14 @@ async def _save_comparison(tenant_key: str, payload: dict[str, Any]) -> None:
|
|||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO quote_comparisons
|
INSERT INTO quote_comparisons
|
||||||
(tenant_key, comparison_id, recommended_vendor, score, normalized_total, payload, updated_at)
|
(tenant_key, comparison_id, recommended_vendor, recommendation_vendor,
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, NOW())
|
score, weighted_score, normalized_total, payload, updated_at)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, NOW())
|
||||||
ON CONFLICT (tenant_key, comparison_id) DO UPDATE SET
|
ON CONFLICT (tenant_key, comparison_id) DO UPDATE SET
|
||||||
recommended_vendor = EXCLUDED.recommended_vendor,
|
recommended_vendor = EXCLUDED.recommended_vendor,
|
||||||
|
recommendation_vendor = EXCLUDED.recommendation_vendor,
|
||||||
score = EXCLUDED.score,
|
score = EXCLUDED.score,
|
||||||
|
weighted_score = EXCLUDED.weighted_score,
|
||||||
normalized_total = EXCLUDED.normalized_total,
|
normalized_total = EXCLUDED.normalized_total,
|
||||||
payload = EXCLUDED.payload,
|
payload = EXCLUDED.payload,
|
||||||
updated_at = NOW()
|
updated_at = NOW()
|
||||||
@@ -587,6 +590,8 @@ async def _save_comparison(tenant_key: str, payload: dict[str, Any]) -> None:
|
|||||||
tenant_key,
|
tenant_key,
|
||||||
payload["comparison_id"],
|
payload["comparison_id"],
|
||||||
payload["recommendation"]["vendor"],
|
payload["recommendation"]["vendor"],
|
||||||
|
payload["recommendation"]["vendor"],
|
||||||
|
payload["recommendation"]["score"],
|
||||||
payload["recommendation"]["score"],
|
payload["recommendation"]["score"],
|
||||||
payload["recommendation"]["normalized_total"],
|
payload["recommendation"]["normalized_total"],
|
||||||
json.dumps(payload),
|
json.dumps(payload),
|
||||||
@@ -645,16 +650,18 @@ async def _persist_receipt(
|
|||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO quote_execution_receipts
|
INSERT INTO quote_execution_receipts
|
||||||
(tenant_key, comparison_id, receipt_id, skill_name, status, input_hash,
|
(tenant_key, comparison_id, receipt_id, skill_name, tool_name, status, ok,
|
||||||
result_hash, payload, created_at)
|
input_hash, result_hash, payload, created_at)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, NOW())
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
tenant_key,
|
tenant_key,
|
||||||
comparison_id,
|
comparison_id,
|
||||||
receipt["receipt_id"],
|
receipt["receipt_id"],
|
||||||
skill_name,
|
skill_name,
|
||||||
|
skill_name,
|
||||||
status,
|
status,
|
||||||
|
status == "ok",
|
||||||
receipt["input_hash"],
|
receipt["input_hash"],
|
||||||
receipt["result_hash"],
|
receipt["result_hash"],
|
||||||
json.dumps(receipt),
|
json.dumps(receipt),
|
||||||
|
|||||||
19
db/migrations/003_quotejudge_legacy_bridge.sql
Normal file
19
db/migrations/003_quotejudge_legacy_bridge.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- Bridge the earliest QuoteJudge schema and the current typed schema without
|
||||||
|
-- dropping data or weakening historical NOT NULL constraints.
|
||||||
|
ALTER TABLE quote_comparisons
|
||||||
|
ADD COLUMN IF NOT EXISTS recommendation_vendor TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS weighted_score NUMERIC(10,4);
|
||||||
|
|
||||||
|
UPDATE quote_comparisons
|
||||||
|
SET recommendation_vendor = COALESCE(recommendation_vendor, recommended_vendor),
|
||||||
|
weighted_score = COALESCE(weighted_score, score)
|
||||||
|
WHERE recommendation_vendor IS NULL OR weighted_score IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE quote_execution_receipts
|
||||||
|
ADD COLUMN IF NOT EXISTS tool_name TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS ok BOOLEAN;
|
||||||
|
|
||||||
|
UPDATE quote_execution_receipts
|
||||||
|
SET tool_name = COALESCE(tool_name, skill_name),
|
||||||
|
ok = COALESCE(ok, status = 'ok')
|
||||||
|
WHERE tool_name IS NULL OR ok IS NULL;
|
||||||
@@ -60,6 +60,11 @@ def test_full_stack_product_contract():
|
|||||||
|
|
||||||
migrations = list((ROOT / "db" / "migrations").glob("*.sql"))
|
migrations = list((ROOT / "db" / "migrations").glob("*.sql"))
|
||||||
assert migrations and all(path.read_text(encoding="utf-8").strip() for path in migrations)
|
assert migrations and all(path.read_text(encoding="utf-8").strip() for path in migrations)
|
||||||
|
compatibility = (ROOT / "db" / "migrations" / "003_quotejudge_legacy_bridge.sql").read_text()
|
||||||
|
assert "recommendation_vendor" in compatibility
|
||||||
|
assert "tool_name" in compatibility
|
||||||
|
assert "recommendation_vendor = EXCLUDED.recommendation_vendor" in source
|
||||||
|
assert "tool_name, status, ok" in source
|
||||||
|
|
||||||
card = load_local_project(ROOT).agent_cls().card()
|
card = load_local_project(ROOT).agent_cls().card()
|
||||||
skill_names = {skill.name for skill in card.skills}
|
skill_names = {skill.name for skill in card.skills}
|
||||||
|
|||||||
Reference in New Issue
Block a user