From 95ffb50a3a5e9e30a143b83fa10a40998be02878 Mon Sep 17 00:00:00 2001 From: Robert Date: Sat, 18 Jul 2026 02:04:26 -0300 Subject: [PATCH] Restore QuoteJudge upload tool compatibility --- a2a.yaml | 2 +- agent.py | 52 +++++++++++++++++++++++++++++-- tests/test_full_stack_contract.py | 12 +++++-- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/a2a.yaml b/a2a.yaml index ea9d886..25c99fe 100644 --- a/a2a.yaml +++ b/a2a.yaml @@ -1,5 +1,5 @@ name: quote-judge-studio-v1 -version: 0.1.0 +version: 0.1.2 entrypoint: agent:QuoteJudgeStudioV1 expose: public: false diff --git a/agent.py b/agent.py index f08476d..8485140 100644 --- a/agent.py +++ b/agent.py @@ -8,7 +8,6 @@ Deterministic, no-LLM quote comparison product: """ from __future__ import annotations -import asyncio import base64 import csv import hashlib @@ -88,7 +87,7 @@ class QuoteJudgeStudioV1(A2AAgent[QuoteJudgeStudioV1Config, PlatformUserAuth]): "and warranty scoring, persists recommendations, supports upload/paste " "workflows, and exposes typed A2A/MCP tools." ) - version = "0.1.1" + version = "0.1.2" config_model = QuoteJudgeStudioV1Config auth_model = PlatformUserAuth @@ -208,6 +207,26 @@ class QuoteJudgeStudioV1(A2AAgent[QuoteJudgeStudioV1Config, PlatformUserAuth]): return {**parsed, "comparison_id": comparison_id} return await self.compare_quotes(ctx, comparison_id=comparison_id, quotes=parsed["quotes"], weights=weights) + @a2a.tool( + description="Compatibility alias for the original QuoteJudge browser upload tool.", + timeout_seconds=60, + idempotent=True, + cost_class="deterministic", + ) + async def compare_uploaded_quotes_browser( + self, + ctx: RunContext[PlatformUserAuth], + comparison_id: Annotated[str, Field(min_length=1, max_length=120)], + documents: Annotated[list[BrowserDocument], Field(min_length=1, max_length=MAX_BROWSER_DOCUMENTS)], + weights: QuoteWeights, + ) -> dict[str, Any]: + return await self.compare_quotes_from_browser_upload( + ctx, + comparison_id=comparison_id, + documents=documents, + weights=weights, + ) + @a2a.tool( description=( "External API upload path: accept a typed FileUpload containing " @@ -257,6 +276,35 @@ class QuoteJudgeStudioV1(A2AAgent[QuoteJudgeStudioV1Config, PlatformUserAuth]): return {**parsed, "comparison_id": comparison_id} return await self.compare_quotes(ctx, comparison_id=comparison_id, quotes=parsed["quotes"], weights=weights) + @a2a.tool( + description="Compatibility alias for the original QuoteJudge external upload tool.", + timeout_seconds=60, + idempotent=True, + cost_class="deterministic", + grant_mode="read_only", + grant_allow_patterns=("**",), + ) + async def compare_uploaded_quote_file( + self, + ctx: RunContext[PlatformUserAuth], + comparison_id: Annotated[str, Field(min_length=1, max_length=120)], + document: Annotated[ + UploadedFile, + FileUpload( + accept=ACCEPTED_UPLOAD_TYPES, + max_bytes=MAX_BROWSER_DOCUMENT_BYTES, + description="JSON list/object, CSV, or text containing vendor quotes.", + ), + ], + weights: QuoteWeights, + ) -> dict[str, Any]: + return await self.compare_quotes_from_upload( + ctx, + comparison_id=comparison_id, + quote_file=document, + weights=weights, + ) + def _tenant_key(ctx: RunContext[PlatformUserAuth]) -> str: auth = ctx.auth diff --git a/tests/test_full_stack_contract.py b/tests/test_full_stack_contract.py index 3973991..760b87a 100644 --- a/tests/test_full_stack_contract.py +++ b/tests/test_full_stack_contract.py @@ -1,7 +1,6 @@ from __future__ import annotations import asyncio -import os from pathlib import Path from unittest.mock import patch @@ -42,7 +41,16 @@ def test_full_stack_product_contract(): card = load_local_project(ROOT).agent_cls().card() skill_names = {skill.name for skill in card.skills} - assert {"compare_quotes", "get_comparison", "compare_quotes_from_browser_upload", "compare_quotes_from_upload"}.issubset(skill_names) + assert { + "compare_quotes", + "get_comparison", + "compare_quotes_from_browser_upload", + "compare_quotes_from_upload", + "compare_uploaded_quotes_browser", + "compare_uploaded_quote_file", + }.issubset(skill_names) + assert card.version == "0.1.2" + assert "version: 0.1.2" in (ROOT / "a2a.yaml").read_text(encoding="utf-8") databases = card.runtime.platform_resources.databases assert databases, "live Agent Card must declare its managed database" assert databases[0].scope == "user"