File size: 4,473 Bytes
080cf2c
d7e064f
080cf2c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d7e064f
080cf2c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d7e064f
080cf2c
 
 
d7e064f
080cf2c
 
 
d7e064f
080cf2c
 
d7e064f
080cf2c
 
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
import requests
from logger import log_info, log_error, log_warning, log_debug

class APIConnector:
    def __init__(self, service_config):
        self.service_config = service_config

    def resolve_placeholders(self, template, session):
        resolved = template
        for key, value in session.variables.items():
            resolved = resolved.replace(f"{{variables.{key}}}", str(value))
        for api, tokens in session.auth_tokens.items():
            resolved = resolved.replace(f"{{auth_tokens.{api}.token}}", tokens.get("token", ""))
        return resolved

    def get_auth_token(self, api_name, auth_config, session):
        auth_endpoint = auth_config.get("auth_endpoint")
        auth_body = {
            k: self.resolve_placeholders(str(v), session)
            for k, v in auth_config.get("auth_body", {}).items()
        }
        token_path = auth_config.get("auth_token_path")

        response = requests.post(auth_endpoint, json=auth_body, timeout=5)
        response.raise_for_status()
        json_resp = response.json()

        token = json_resp
        for part in token_path.split("."):
            token = token.get(part)
            if token is None:
                raise Exception(f"Could not resolve token path: {token_path}")

        refresh_token = json_resp.get("refresh_token")
        session.auth_tokens[api_name] = {"token": token, "refresh_token": refresh_token}

        log(f"πŸ”‘ Retrieved auth token for {api_name}")
        return token

    def refresh_auth_token(self, api_name, auth_config, session):
        refresh_endpoint = auth_config.get("auth_refresh_endpoint")
        refresh_body = {
            k: self.resolve_placeholders(str(v), session)
            for k, v in auth_config.get("refresh_body", {}).items()
        }
        token_path = auth_config.get("auth_token_path")

        response = requests.post(refresh_endpoint, json=refresh_body, timeout=5)
        response.raise_for_status()
        json_resp = response.json()

        token = json_resp
        for part in token_path.split("."):
            token = token.get(part)
            if token is None:
                raise Exception(f"Could not resolve token path: {token_path}")

        new_refresh_token = json_resp.get("refresh_token", session.auth_tokens[api_name].get("refresh_token"))
        session.auth_tokens[api_name] = {"token": token, "refresh_token": new_refresh_token}

        log_info(f"πŸ” Refreshed auth token for {api_name}")
        return token

    def call_api(self, intent_def, session):
        api_name = intent_def.get("action")
        api_def = self.service_config.get_api_config(api_name)
        if not api_def:
            raise Exception(f"API config not found: {api_name}")

        url = api_def["url"]
        method = api_def.get("method", "POST")
        headers = {h["key"]: self.resolve_placeholders(h["value"], session) for h in api_def.get("headers", [])}
        body = {k: self.resolve_placeholders(str(v), session) for k, v in api_def.get("body", {}).items()}
        timeout = api_def.get("timeout", 5)
        retry_count = api_def.get("retry_count", 0)
        auth_config = api_def.get("auth")

        # Get auth token if needed
        if auth_config and api_name not in session.auth_tokens:
            self.get_auth_token(api_name, auth_config, session)

        for attempt in range(retry_count + 1):
            try:
                response = requests.request(method, url, headers=headers, json=body, timeout=timeout)
                if response.status_code == 401 and auth_config and attempt < retry_count:
                    log_info(f"πŸ” Token expired for {api_name}, refreshing...")
                    self.refresh_auth_token(api_name, auth_config, session)
                    continue
                response.raise_for_status()
                log_info(f"βœ… API call successful: {api_name}")
                return response.json()
            except requests.Timeout:
                fallback = intent_def.get("fallback_timeout_message", "This operation is currently unavailable.")
                log_warning(f"⚠️ API timeout for {api_name} β†’ {fallback}")
                return {"fallback": fallback}
            except Exception as e:
                log_error(f"❌ API call error for {api_name}", e)
                fallback = intent_def.get("fallback_error_message", "An error occurred during the operation.")
                return {"fallback": fallback}