a2a-source-edit: write agent.py

This commit is contained in:
a2a-cloud
2026-07-18 07:14:23 +00:00
parent 7d5c62a07e
commit 76d8506d38

View File

@@ -26,13 +26,15 @@ from a2a_pack import (
AgentDatabaseEnv,
AgentDatabaseMigrations,
AgentPlatformResources,
FileUpload,
PlatformUserAuth,
Pricing,
Resources,
RunContext,
State,
UploadedFile,
FileUpload,
WorkspaceAccess,
WorkspaceMode,
)
MAX_TEXT_CHARS = 200_000
@@ -133,7 +135,7 @@ class ContractClockStudioV1(A2AAgent[ContractClockStudioV1Config, PlatformUserAu
config_model = ContractClockStudioV1Config
auth_model = PlatformUserAuth
# Deterministic local logic only: no LLM credential is required.
# Deterministic local logic only: no LLM credential is read or required.
pricing = Pricing(
price_per_call_usd=0.0,
caller_pays_llm=False,
@@ -142,6 +144,12 @@ class ContractClockStudioV1(A2AAgent[ContractClockStudioV1Config, PlatformUserAu
resources = Resources(cpu="500m", memory="512Mi", max_runtime_seconds=120)
state = State.DURABLE
tools_used = ("postgres", "mcp")
workspace_access = WorkspaceAccess.dynamic(
max_files=4,
allowed_modes=(WorkspaceMode.READ_ONLY,),
require_reason=False,
max_total_size_bytes=MAX_UPLOAD_BYTES,
)
platform_resources = AgentPlatformResources(
databases=(
AgentDatabase(
@@ -194,7 +202,6 @@ class ContractClockStudioV1(A2AAgent[ContractClockStudioV1Config, PlatformUserAu
persist_contract(tenant, clean_id, clean_title, payload, receipt_id)
persist_receipt(tenant, receipt_id, "analyze_contract", clean_id, payload, "ok")
except Exception:
# Fail closed: analysis without durable storage is not a success for this product.
return AnalyzeResult(
ok=False,
contract_id=clean_id,
@@ -262,20 +269,16 @@ class ContractClockStudioV1(A2AAgent[ContractClockStudioV1Config, PlatformUserAu
raise ValidationFailure("file_too_large", "Upload is larger than 256 KiB.")
if document.media_type not in ALLOWED_MEDIA_TYPES:
raise ValidationFailure("unsupported_media_type", "Only plain text uploads are supported.")
grant = await ctx.workspace.request_access(
await ctx.workspace.request_access(
files=[document.path],
mode=a2a.WorkspaceMode.READ_ONLY,
mode=WorkspaceMode.READ_ONLY,
reason="Read the caller-uploaded contract text for deadline extraction.",
purpose="contract upload analysis",
)
view = await ctx.workspace.open_view(
purpose="contract upload analysis",
hints=[document.path],
max_files=1,
mode=a2a.WorkspaceMode.READ_ONLY,
reason=f"Read uploaded file under grant {grant.grant_id}.",
)
raw = await view.read(document.path)
read_bytes = getattr(ctx.workspace, "read_bytes", None)
if read_bytes is None:
raise RuntimeError("workspace backend does not expose direct file reads")
raw = read_bytes(document.path)
if len(raw) > MAX_UPLOAD_BYTES:
raise ValidationFailure("file_too_large", "Upload is larger than 256 KiB.")
text = raw.decode("utf-8")
@@ -406,15 +409,14 @@ def extract_timeline(text: str) -> ExtractedTimeline:
warnings: list[str] = []
renewal_dates = []
for parsed, excerpt in dates:
if RENEWAL_RE.search(excerpt) or RENEWAL_RE.search(text[max(0, text.find(parsed.isoformat()) - 160): text.find(parsed.isoformat()) + 160]):
date_token = parsed.isoformat()
date_index = text.find(date_token)
local_context = text[max(0, date_index - 160): date_index + 160] if date_index >= 0 else excerpt
if RENEWAL_RE.search(excerpt) or RENEWAL_RE.search(local_context):
renewal_dates.append(parsed)
deadlines.append(
Deadline(kind="renewal", date=parsed.isoformat(), summary="Automatic renewal date explicitly stated in contract.", source_text=excerpt)
)
deadlines.append(Deadline(kind="renewal", date=date_token, summary="Automatic renewal date explicitly stated in contract.", source_text=excerpt))
else:
deadlines.append(
Deadline(kind="obligation", date=parsed.isoformat(), summary="Explicit dated obligation stated in contract.", source_text=excerpt)
)
deadlines.append(Deadline(kind="obligation", date=date_token, summary="Explicit dated obligation stated in contract.", source_text=excerpt))
notice_match = NOTICE_RE.search(text)
if notice_match:
@@ -434,7 +436,6 @@ def extract_timeline(text: str) -> ExtractedTimeline:
elif RENEWAL_RE.search(text):
warnings.append("No explicit notice-window duration was found for the renewal date.")
# Acceptance and UI prefer renewal before notice before other dated obligations.
order = {"renewal": 0, "notice": 1, "obligation": 2}
deduped: dict[tuple[str, str], Deadline] = {}
for deadline in sorted(deadlines, key=lambda item: (order[item.kind], item.date, item.summary)):