|
| 1 | +#!/usr/bin/env python |
| 2 | +""" |
| 3 | +Quick demo script - shows failure then success within ~1 minute. |
| 4 | +First item fails inspection, second item passes. |
| 5 | +""" |
| 6 | + |
| 7 | +import os |
| 8 | +import sys |
| 9 | +import asyncio |
| 10 | +from datetime import datetime |
| 11 | + |
| 12 | +from temporalio.client import Client |
| 13 | + |
| 14 | +from project.models.events import ( |
| 15 | + EventType, |
| 16 | + InspectionFailedEvent, |
| 17 | + InspectionPassedEvent, |
| 18 | + SubmitalApprovalEvent, |
| 19 | + ShipmentArrivedSiteEvent, |
| 20 | + ShipmentDepartedFactoryEvent, |
| 21 | +) |
| 22 | +from agentex.lib.utils.logging import make_logger |
| 23 | +from agentex.lib.environment_variables import EnvironmentVariables |
| 24 | + |
| 25 | +# Set defaults for local development |
| 26 | +os.environ.setdefault("AGENT_NAME", "procurement-agent") |
| 27 | +os.environ.setdefault("ACP_URL", "http://localhost:8000") |
| 28 | +os.environ.setdefault("WORKFLOW_NAME", "procurement-agent") |
| 29 | +os.environ.setdefault("WORKFLOW_TASK_QUEUE", "procurement_agent_queue") |
| 30 | +os.environ.setdefault("TEMPORAL_ADDRESS", "localhost:7233") |
| 31 | + |
| 32 | +logger = make_logger(__name__) |
| 33 | +environment_variables = EnvironmentVariables.refresh() |
| 34 | + |
| 35 | +# Delay between events (seconds) - keep short for demo |
| 36 | +EVENT_DELAY = 3 |
| 37 | +# Longer delay after inspection failure to let user see the failure handling |
| 38 | +POST_FAILURE_DELAY = 20 |
| 39 | + |
| 40 | + |
| 41 | +async def send_demo_events(workflow_id: str): |
| 42 | + """Send demo events: one failure cycle, one success cycle.""" |
| 43 | + |
| 44 | + # Connect to Temporal |
| 45 | + temporal_url = environment_variables.TEMPORAL_ADDRESS or "localhost:7233" |
| 46 | + client = await Client.connect(temporal_url) |
| 47 | + |
| 48 | + # Get handle to the workflow |
| 49 | + handle = client.get_workflow_handle(workflow_id) |
| 50 | + |
| 51 | + # Item 1: HVAC Units - will FAIL inspection |
| 52 | + # Required by: 2026-03-01, Buffer: 7 days |
| 53 | + # Arriving on 2026-02-15 (14 days early - well within buffer, no issue flagged) |
| 54 | + hvac_events = [ |
| 55 | + SubmitalApprovalEvent( |
| 56 | + event_type=EventType.SUBMITTAL_APPROVED, |
| 57 | + item="HVAC Units", |
| 58 | + document_name="HVAC Units Submittal.pdf", |
| 59 | + document_url="/submittal_approval.pdf" |
| 60 | + ), |
| 61 | + ShipmentDepartedFactoryEvent( |
| 62 | + event_type=EventType.SHIPMENT_DEPARTED_FACTORY, |
| 63 | + item="HVAC Units", |
| 64 | + eta=datetime(2026, 2, 15, 11, 0), |
| 65 | + date_departed=datetime(2026, 2, 8, 13, 45), |
| 66 | + location_address="218 W 18th St, New York, NY 10011" |
| 67 | + ), |
| 68 | + ShipmentArrivedSiteEvent( |
| 69 | + event_type=EventType.SHIPMENT_ARRIVED_SITE, |
| 70 | + item="HVAC Units", |
| 71 | + date_arrived=datetime(2026, 2, 15, 10, 30), |
| 72 | + location_address="650 Townsend St, San Francisco, CA 94103" |
| 73 | + ), |
| 74 | + InspectionFailedEvent( |
| 75 | + event_type=EventType.INSPECTION_FAILED, |
| 76 | + item="HVAC Units", |
| 77 | + inspection_date=datetime(2026, 2, 16, 14, 15), |
| 78 | + document_name="HVAC Units Inspection Report.pdf", |
| 79 | + document_url="/inspection_failed.pdf" |
| 80 | + ) |
| 81 | + ] |
| 82 | + |
| 83 | + # Item 2: Steel Beams - will PASS inspection |
| 84 | + # Required by: 2026-02-15, Buffer: 5 days |
| 85 | + # Arriving on 2026-02-10 (5 days early - within buffer) |
| 86 | + steel_events = [ |
| 87 | + SubmitalApprovalEvent( |
| 88 | + event_type=EventType.SUBMITTAL_APPROVED, |
| 89 | + item="Steel Beams", |
| 90 | + document_name="Steel Beams Submittal.pdf", |
| 91 | + document_url="/submittal_approval.pdf" |
| 92 | + ), |
| 93 | + ShipmentDepartedFactoryEvent( |
| 94 | + event_type=EventType.SHIPMENT_DEPARTED_FACTORY, |
| 95 | + item="Steel Beams", |
| 96 | + eta=datetime(2026, 2, 10, 14, 30), |
| 97 | + date_departed=datetime(2026, 2, 3, 9, 15), |
| 98 | + location_address="218 W 18th St, New York, NY 10011" |
| 99 | + ), |
| 100 | + ShipmentArrivedSiteEvent( |
| 101 | + event_type=EventType.SHIPMENT_ARRIVED_SITE, |
| 102 | + item="Steel Beams", |
| 103 | + date_arrived=datetime(2026, 2, 10, 15, 45), |
| 104 | + location_address="650 Townsend St, San Francisco, CA 94103" |
| 105 | + ), |
| 106 | + InspectionPassedEvent( |
| 107 | + event_type=EventType.INSPECTION_PASSED, |
| 108 | + item="Steel Beams", |
| 109 | + inspection_date=datetime(2026, 2, 11, 10, 20), |
| 110 | + document_name="Steel Beams Inspection Report.pdf", |
| 111 | + document_url="/inspection_passed.pdf" |
| 112 | + ) |
| 113 | + ] |
| 114 | + |
| 115 | + all_events = [ |
| 116 | + ("HVAC Units (will FAIL)", hvac_events, True), # True = has failure, wait longer after |
| 117 | + ("Steel Beams (will PASS)", steel_events, False), |
| 118 | + ] |
| 119 | + |
| 120 | + print(f"Connected to workflow: {workflow_id}") |
| 121 | + print("=" * 60) |
| 122 | + print("QUICK DEMO: Failure → Success") |
| 123 | + print(f"Event delay: {EVENT_DELAY}s, Post-failure delay: {POST_FAILURE_DELAY}s") |
| 124 | + print("=" * 60) |
| 125 | + |
| 126 | + for item_name, events, has_failure in all_events: |
| 127 | + print(f"\n{'=' * 60}") |
| 128 | + print(f"Processing: {item_name}") |
| 129 | + print("=" * 60) |
| 130 | + |
| 131 | + for i, event in enumerate(events, 1): |
| 132 | + print(f"\n[{i}/4] Sending: {event.event_type.value}") |
| 133 | + print(f" Item: {event.item}") |
| 134 | + |
| 135 | + if hasattr(event, 'eta'): |
| 136 | + print(f" ETA: {event.eta}") |
| 137 | + if hasattr(event, 'date_arrived'): |
| 138 | + print(f" Date Arrived: {event.date_arrived}") |
| 139 | + if hasattr(event, 'inspection_date'): |
| 140 | + print(f" Inspection Date: {event.inspection_date}") |
| 141 | + |
| 142 | + try: |
| 143 | + event_data = event.model_dump_json() |
| 144 | + await handle.signal("send_event", event_data) |
| 145 | + print(f" ✓ Sent!") |
| 146 | + |
| 147 | + # Use longer delay after inspection failure |
| 148 | + is_last_event = (i == len(events)) |
| 149 | + if is_last_event and has_failure: |
| 150 | + print(f" ⏳ Waiting {POST_FAILURE_DELAY}s for failure handling...") |
| 151 | + await asyncio.sleep(POST_FAILURE_DELAY) |
| 152 | + else: |
| 153 | + await asyncio.sleep(EVENT_DELAY) |
| 154 | + |
| 155 | + except Exception as e: |
| 156 | + print(f" ✗ Error: {e}") |
| 157 | + logger.error(f"Failed to send event: {e}") |
| 158 | + |
| 159 | + print("\n" + "=" * 60) |
| 160 | + print("Demo complete! Check the UI to see processed events.") |
| 161 | + print("=" * 60) |
| 162 | + |
| 163 | + |
| 164 | +async def main(): |
| 165 | + """Main entry point.""" |
| 166 | + |
| 167 | + if len(sys.argv) > 1: |
| 168 | + workflow_id = sys.argv[1] |
| 169 | + else: |
| 170 | + print("Enter Workflow ID:") |
| 171 | + workflow_id = input("Workflow ID: ").strip() |
| 172 | + |
| 173 | + if not workflow_id: |
| 174 | + print("Error: Workflow ID required!") |
| 175 | + print("\nUsage: python send_test_events_lite.py [workflow_id]") |
| 176 | + return |
| 177 | + |
| 178 | + try: |
| 179 | + await send_demo_events(workflow_id) |
| 180 | + except KeyboardInterrupt: |
| 181 | + print("\n\nInterrupted. Goodbye!") |
| 182 | + except Exception as e: |
| 183 | + logger.error(f"Unexpected error: {e}") |
| 184 | + print(f"Error: {e}") |
| 185 | + print("\nMake sure:") |
| 186 | + print("1. The workflow is running") |
| 187 | + print("2. The workflow ID is correct") |
| 188 | + print("3. Temporal is accessible at", environment_variables.TEMPORAL_ADDRESS) |
| 189 | + |
| 190 | + |
| 191 | +if __name__ == "__main__": |
| 192 | + asyncio.run(main()) |
0 commit comments