File size: 5,612 Bytes
ce3b075
5aa95b3
 
 
689e710
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229832a
689e710
 
 
 
 
97d2a3d
 
689e710
5f7e666
 
5aa95b3
5f7e666
5aa95b3
 
689e710
97d2a3d
689e710
 
 
 
 
 
d653955
0d53358
689e710
 
0cc7808
5aa95b3
 
 
 
 
97d2a3d
7e39dbf
 
5aa95b3
7e39dbf
6454f76
689e710
 
 
5f7e666
 
 
 
 
 
 
 
 
 
 
689e710
 
5f7e666
689e710
229832a
 
 
689e710
 
 
229832a
 
 
 
 
 
 
 
 
5f7e666
 
 
 
 
 
 
229832a
5f7e666
229832a
689e710
5f7e666
5aa95b3
5f7e666
689e710
5f7e666
689e710
 
229832a
5f7e666
 
689e710
 
 
 
 
 
 
 
 
 
5f7e666
6f61f21
5f7e666
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import gevent.monkey
gevent.monkey.patch_all(asyncio=True) # Keep this at the very top

import asyncio # Keep this
from flask import Flask, request, jsonify
from proxy_lite import Runner, RunnerConfig
import os
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

app = Flask(__name__)

_runner = None

async def initialize_runner():
    global _runner
    if _runner is None:
        logger.info("Initializing Proxy-lite Runner...")
        
        hf_api_token = os.environ.get("HF_API_TOKEN")
        if not hf_api_token:
            logger.error("HF_API_TOKEN environment variable not set. Cannot initialize Runner.")
            raise ValueError("HF_API_TOKEN environment variable not set. Please set it as a Space secret.")

        config = RunnerConfig.from_dict({
            "environment": {
                "name": "webbrowser",
                "homepage": "https://dwd000006jia1mae.lightning.force.com/lightning/setup/AccountForecastSettings/home",
                "headless": True,
                "launch_args": ["--no-sandbox", "--disable-setuid-sandbox"],
                "screenshot_delay": 3.0,
                "include_html": True,
                "include_poi_text": True,
            },
            "solver": {
                "name": "simple",
                "agent": {
                    "name": "proxy_lite",
                    "client": {
                        "name": "convergence",
                        "model_id": "convergence-ai/proxy-lite-3b",
                        "api_base": "https://convergence-ai-demo-api.hf.space/v1", 
                        "api_key": hf_api_token
                    }
                }
            },
            "environment_timeout": 1800.0,
            "action_timeout": 1800.0,
            "task_timeout": 18000.0,
            "max_steps": 150,
            "logger_level": "DEBUG",
        })

        logger.info(f"DEBUG: app.py - Initializing Runner with environment_timeout: {config.environment_timeout} seconds")
        logger.info(f"DEBUG: app.py - Full config used: {config.model_dump_json(indent=2)}")

        _runner = Runner(config=config)
        logger.info("Proxy-lite Runner initialized successfully.")
    return _runner

# --- MODIFIED run_async_task FUNCTION (SIMPLIFIED) ---
# This function is no longer needed in most cases with gevent.monkey.patch_all(asyncio=True)
# but if you must call async functions from sync context, you simply await them.
# However, you are already in an async function context within Flask routes when using Gunicorn/gevent.
# The Gunicorn worker itself implicitly runs an event loop.
# Let's remove the run_until_complete part.

# DELETED: def run_async_task(coro): ...

# --- END MODIFIED run_async_task FUNCTION ---


@app.route('/run_proxy_task', methods=['POST'])
async def run_proxy_task_endpoint(): # <--- MAKE THIS FUNCTION ASYNC
    data = request.json
    request_task_instruction = data.get('task')

    if not request_task_instruction:
        logger.warning("Received request without 'task' field. Returning 400.")
        return jsonify({"error": "No 'task' provided in request body"}), 400

    logger.info(f"Received user request task: '{request_task_instruction}'")

    salesforce_username = os.environ.get("SALESFORCE_USERNAME")
    salesforce_password = os.environ.get("SALESFORCE_PASSWORD")

    if not salesforce_username or not salesforce_password:
        logger.error("Salesforce credentials (SALESFORCE_USERNAME, SALESFORCE_PASSWORD) environment variables not set.")
        return jsonify({"error": "Salesforce credentials not configured. Please set SALESFORCE_USERNAME and SALESFORCE_PASSWORD as Space secrets."}), 500

    agent_task = (
        f"Log in to Salesforce. The username is '{salesforce_username}' and the password is '{salesforce_password}'. "
        f"After attempting to log in, observe the page carefully. "
        f"If the login was successful, the URL should change from the login page, and you should see elements indicating a logged-in state (e.g., a Salesforce navigation menu, a home screen, or a profile icon), rather than a login form or an error message. "
        f"If the login is successful, {request_task_instruction}. "
        f"Report the final status of the requested action and confirmation of successful login."
    )
    
    logger.info(f"Executing agent task: '{agent_task[:200]}...'")

    try:
        # Since run_proxy_task_endpoint is now async, you can directly await
        runner = await initialize_runner()
        result = await runner.run(agent_task) # <--- AWAIT DIRECTLY

        logger.info(f"Proxy-lite task completed. Output: {result[:200]}...")
        return jsonify({"output": result})
    except Exception as e:
        logger.exception(f"Error processing Salesforce task: {e}")
        # The RuntimeWarning: coroutine 'initialize_runner' was never awaited will disappear
        # because initialize_runner is now awaited.
        return jsonify({"error": f"An error occurred: {str(e)}. Check logs for details."}), 500

@app.route('/')
def root():
    logger.info("Root endpoint accessed.")
    return "Proxy-lite API is running. Send POST requests to /run_proxy_task with a 'task' in JSON body."

if __name__ == '__main__':
    if not os.environ.get("HF_API_TOKEN"):
        logger.error("HF_API_TOKEN environment variable is not set. Please set it for local testing.")
        exit(1)
    logger.info("Starting Flask development server on 0.0.0.0:7860...")
    app.run(host='0.0.0.0', port=7860, debug=True)