hyperforge-external 1.0.0.post21__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hyperforge_external/__init__.py +3 -0
- hyperforge_external/agent.py +136 -0
- hyperforge_external/config.py +71 -0
- hyperforge_external-1.0.0.post21.dist-info/METADATA +19 -0
- hyperforge_external-1.0.0.post21.dist-info/RECORD +7 -0
- hyperforge_external-1.0.0.post21.dist-info/WHEEL +5 -0
- hyperforge_external-1.0.0.post21.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from copy import deepcopy
|
|
2
|
+
from time import time
|
|
3
|
+
|
|
4
|
+
from hyperforge.agent import Agent
|
|
5
|
+
from hyperforge.configure import agent
|
|
6
|
+
from hyperforge.manager import Manager
|
|
7
|
+
from hyperforge.memory import QuestionMemory
|
|
8
|
+
from hyperforge.trace import trace_agent
|
|
9
|
+
from hyperforge.utils import check_dns
|
|
10
|
+
from hyperforge.utils.http import safe_http_client
|
|
11
|
+
|
|
12
|
+
from hyperforge import PROMPT_ENVIRONMENT, logger
|
|
13
|
+
from hyperforge_external.config import ExternalCallAgentConfig
|
|
14
|
+
|
|
15
|
+
EXTERNAL_CALL_PROMPT = """
|
|
16
|
+
Collect the parameters to call the query based on the schema and the context:
|
|
17
|
+
{{prompt}}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
[START OF CONTEXT]
|
|
21
|
+
{{context}}
|
|
22
|
+
[END OF CONTEXT]
|
|
23
|
+
|
|
24
|
+
MAIN QUESTION: {{question}}
|
|
25
|
+
|
|
26
|
+
MAIN ANSWER: {{answer}}
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
EXTERNAL_CALL_PROMPT_TEMPLATE = PROMPT_ENVIRONMENT.from_string(EXTERNAL_CALL_PROMPT)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@agent(
|
|
33
|
+
id="external",
|
|
34
|
+
agent_type="postprocess",
|
|
35
|
+
title="External Call",
|
|
36
|
+
description="Agent that performs External Call.",
|
|
37
|
+
config_schema=ExternalCallAgentConfig,
|
|
38
|
+
)
|
|
39
|
+
class ExternalCallAgent(Agent[ExternalCallAgentConfig]):
|
|
40
|
+
config: ExternalCallAgentConfig
|
|
41
|
+
|
|
42
|
+
@trace_agent
|
|
43
|
+
async def __call__(
|
|
44
|
+
self,
|
|
45
|
+
memory: QuestionMemory,
|
|
46
|
+
manager: Manager,
|
|
47
|
+
):
|
|
48
|
+
t0 = time()
|
|
49
|
+
|
|
50
|
+
prompt = EXTERNAL_CALL_PROMPT_TEMPLATE.render(
|
|
51
|
+
question=memory.original_question,
|
|
52
|
+
context=memory.contexts_minimal(),
|
|
53
|
+
answer=memory.final_answer,
|
|
54
|
+
prompt=self.config.prompt,
|
|
55
|
+
)
|
|
56
|
+
t0 = time()
|
|
57
|
+
|
|
58
|
+
resp = None
|
|
59
|
+
|
|
60
|
+
input_nuclia_tokens: float = 0.0
|
|
61
|
+
output_nuclia_tokens: float = 0.0
|
|
62
|
+
|
|
63
|
+
evaluation = None
|
|
64
|
+
async with safe_http_client() as client:
|
|
65
|
+
url = await check_dns(self.config.url)
|
|
66
|
+
|
|
67
|
+
if self.config.call_schema:
|
|
68
|
+
logger.debug(
|
|
69
|
+
f"Calling external API with schema: {self.config.call_schema}, description: {self.config.description}"
|
|
70
|
+
)
|
|
71
|
+
evaluation, input_tokens, output_tokens = await manager.execute_json(
|
|
72
|
+
user_id="external_call_agent",
|
|
73
|
+
model=self.config.model,
|
|
74
|
+
schema={
|
|
75
|
+
"title": "external_call_agent",
|
|
76
|
+
"description": self.config.description
|
|
77
|
+
or "Choose the parameters to call an external API",
|
|
78
|
+
"parameters": self.config.call_schema,
|
|
79
|
+
},
|
|
80
|
+
prompt=prompt,
|
|
81
|
+
tracking=memory.get_tracking_info(),
|
|
82
|
+
)
|
|
83
|
+
output_nuclia_tokens += output_tokens
|
|
84
|
+
input_nuclia_tokens += input_tokens
|
|
85
|
+
logger.debug(f"Json to do the call: {evaluation}")
|
|
86
|
+
resp = await client.request(
|
|
87
|
+
method=self.config.method.value,
|
|
88
|
+
url=url,
|
|
89
|
+
json=evaluation,
|
|
90
|
+
headers=self.config.headers,
|
|
91
|
+
)
|
|
92
|
+
elif self.config.context:
|
|
93
|
+
logger.debug(
|
|
94
|
+
f"Calling external API with generated context: {memory.contexts}"
|
|
95
|
+
)
|
|
96
|
+
resp = await client.request(
|
|
97
|
+
method=self.config.method.value,
|
|
98
|
+
url=url,
|
|
99
|
+
json=memory.contexts,
|
|
100
|
+
headers=self.config.headers,
|
|
101
|
+
)
|
|
102
|
+
else:
|
|
103
|
+
logger.debug(
|
|
104
|
+
f"Calling external API with call object: {self.config.call_obj}"
|
|
105
|
+
)
|
|
106
|
+
if self.config.call_obj is not None:
|
|
107
|
+
evaluation = deepcopy(self.config.call_obj)
|
|
108
|
+
else:
|
|
109
|
+
evaluation = {}
|
|
110
|
+
evaluation["answer"] = memory.final_answer
|
|
111
|
+
evaluation["question"] = memory.original_question
|
|
112
|
+
resp = await client.request(
|
|
113
|
+
method=self.config.method.value,
|
|
114
|
+
url=self.config.url,
|
|
115
|
+
json=evaluation,
|
|
116
|
+
headers=self.config.headers,
|
|
117
|
+
)
|
|
118
|
+
error_resp = None
|
|
119
|
+
if resp is None:
|
|
120
|
+
error_resp = "No response from external API"
|
|
121
|
+
elif resp.status_code != 200:
|
|
122
|
+
error_resp = f"Error calling external API: {resp.status_code} - {resp.content.decode()}"
|
|
123
|
+
if error_resp:
|
|
124
|
+
logger.error(error_resp)
|
|
125
|
+
raise Exception(error_resp)
|
|
126
|
+
logger.info(f"Response from external API: {resp.content.decode()}")
|
|
127
|
+
await memory.add_step(
|
|
128
|
+
step_module="external",
|
|
129
|
+
step_title=self.step_title(self.config.method.value),
|
|
130
|
+
step_value=self.config.url,
|
|
131
|
+
step_reason=resp.content.decode(),
|
|
132
|
+
timeit=time() - t0,
|
|
133
|
+
step_agent_path=f"/postprocess/{self.config.id if self.config.id else 'default'}",
|
|
134
|
+
input_nuclia_tokens=input_nuclia_tokens,
|
|
135
|
+
output_nuclia_tokens=output_nuclia_tokens,
|
|
136
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any, Dict, Literal, Optional
|
|
3
|
+
|
|
4
|
+
from hyperforge.agent import AgentConfig
|
|
5
|
+
from hyperforge.utils import WidgetType, sync_dns_validation
|
|
6
|
+
from pydantic import Field, field_validator
|
|
7
|
+
from pydantic.config import ConfigDict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Method(str, Enum):
|
|
11
|
+
POST = "POST"
|
|
12
|
+
GET = "GET"
|
|
13
|
+
PATCH = "PATCH"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ExternalCallAgentConfig(AgentConfig):
|
|
17
|
+
model_config = ConfigDict(title="External call")
|
|
18
|
+
module: Literal["external"] = "external"
|
|
19
|
+
prompt: Optional[str] = Field(
|
|
20
|
+
None,
|
|
21
|
+
title="Extra Prompt",
|
|
22
|
+
description="Extra prompt to provide more clues to extract parameters",
|
|
23
|
+
json_schema_extra={
|
|
24
|
+
"show_in_node": True,
|
|
25
|
+
"widget": WidgetType.EXPANDABLE_TEXTAREA,
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
method: Method = Field(
|
|
29
|
+
Method.POST,
|
|
30
|
+
title="Request method",
|
|
31
|
+
description="POST, GET and PATCH are supported",
|
|
32
|
+
)
|
|
33
|
+
description: Optional[str] = Field(
|
|
34
|
+
None,
|
|
35
|
+
title="Description of the operation ",
|
|
36
|
+
description="Description to help the LLM to extract the parameters",
|
|
37
|
+
)
|
|
38
|
+
call_schema: Optional[Dict[str, Any]] = Field(
|
|
39
|
+
None,
|
|
40
|
+
title="JSON Schema to compute parameters ",
|
|
41
|
+
description="Valid JSON Schema to define the parameters to call the URL Its incompatible with call_obj and context",
|
|
42
|
+
)
|
|
43
|
+
call_obj: Optional[Dict[str, Any]] = Field(
|
|
44
|
+
None,
|
|
45
|
+
title="Object to call the endpoint ",
|
|
46
|
+
description="Object that will be used to call the endpoint adding the answer and the question to it. Its incompatible with call_schema and context",
|
|
47
|
+
)
|
|
48
|
+
headers: Dict[str, str] = Field(
|
|
49
|
+
{},
|
|
50
|
+
title="Headers to use on the API call ",
|
|
51
|
+
)
|
|
52
|
+
model: str = Field(
|
|
53
|
+
default="chatgpt-o3-mini",
|
|
54
|
+
title="Generative model",
|
|
55
|
+
description="Model used to extract the parameters to call the URL",
|
|
56
|
+
json_schema_extra={"widget": WidgetType.MODEL_SELECT},
|
|
57
|
+
)
|
|
58
|
+
context: bool = Field(
|
|
59
|
+
False,
|
|
60
|
+
title="Use context as payload",
|
|
61
|
+
description="Use the context as payload. Its incompatible with call_schema and call_obj",
|
|
62
|
+
)
|
|
63
|
+
url: str = Field(
|
|
64
|
+
...,
|
|
65
|
+
title="URL to call",
|
|
66
|
+
description="",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@field_validator("url")
|
|
70
|
+
def validate_url(cls, v):
|
|
71
|
+
return sync_dns_validation(v)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hyperforge_external
|
|
3
|
+
Version: 1.0.0.post21
|
|
4
|
+
Summary: External Hyperforge agent
|
|
5
|
+
Author-email: Nuclia <nucliadb@nuclia.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://progress.com
|
|
8
|
+
Project-URL: Repository, https://github.com/nuclia/forge
|
|
9
|
+
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: <4,>=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: hyperforge
|
|
18
|
+
|
|
19
|
+
# External/Webhook Hyperforge agents
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
hyperforge_external/__init__.py,sha256=XP1agyAfPTWHolRYnIY7M65zDxPrBlhuVMD5YYXJUto,70
|
|
2
|
+
hyperforge_external/agent.py,sha256=x6F1eeeMOuH3lYpIF7GBHyLXa3qiwLyH3LuZht6pCX8,4881
|
|
3
|
+
hyperforge_external/config.py,sha256=17D7FWNcTBSo6tGmbt5sdlHjd7O4AxOtkQ35FR3FfE8,2339
|
|
4
|
+
hyperforge_external-1.0.0.post21.dist-info/METADATA,sha256=9OPp1uX8f-j_VM5mCbkBYL0ArZmfbXX51Rl-M1Dn9Lo,736
|
|
5
|
+
hyperforge_external-1.0.0.post21.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
6
|
+
hyperforge_external-1.0.0.post21.dist-info/top_level.txt,sha256=2lPfd_Xd8E3r3hJ9A4xfdHqmTl5wZ_dOVV1j_J-iHT4,20
|
|
7
|
+
hyperforge_external-1.0.0.post21.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hyperforge_external
|