versionhq 1.2.4.7__py3-none-any.whl → 1.2.4.8__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.
versionhq/__init__.py CHANGED
@@ -25,7 +25,7 @@ from versionhq.tool.rag_tool import RagTool
25
25
  from versionhq.tool.cache_handler import CacheHandler
26
26
  from versionhq.tool.tool_handler import ToolHandler
27
27
  from versionhq.tool.composio.model import ComposioBaseTool
28
- from versionhq.tool.gpt.cup import GPTToolCUP, CUPToolSchema
28
+ from versionhq.tool.gpt.cua import GPTToolCUA, CUAToolSchema
29
29
  from versionhq.tool.gpt.file_search import GPTToolFileSearch, FilterSchema
30
30
  from versionhq.tool.gpt.web_search import GPTToolWebSearch
31
31
  from versionhq.memory.contextual_memory import ContextualMemory
@@ -35,7 +35,7 @@ from versionhq.agent_network.formation import form_agent_network
35
35
  from versionhq.task_graph.draft import workflow
36
36
 
37
37
 
38
- __version__ = "1.2.4.7"
38
+ __version__ = "1.2.4.8"
39
39
  __all__ = [
40
40
  "Agent",
41
41
 
@@ -90,8 +90,8 @@ __all__ = [
90
90
  "ToolHandler",
91
91
  "ComposioBaseTool",
92
92
 
93
- "GPTToolCUP",
94
- "CUPToolSchema",
93
+ "GPTToolCUA",
94
+ "CUAToolSchema",
95
95
  "GPTToolFileSearch",
96
96
  "FilterSchema",
97
97
  "GPTToolWebSearch",
@@ -51,7 +51,7 @@ class Logger(BaseModel):
51
51
  def log(self, level: str, message: str, color="yellow"):
52
52
  if self.verbose:
53
53
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
54
- self._printer.print(f"\n{timestamp} - versionHQ [{level.upper()}]: {message}", color=color)
54
+ self._printer.print(f"\n{timestamp} - vhq [{level.upper()}]: {message}", color=color)
55
55
 
56
56
  self._save(level=level, message=message, filename=self.filename)
57
57
 
versionhq/agent/model.py CHANGED
@@ -126,7 +126,7 @@ class Agent(BaseModel):
126
126
  from versionhq.tool.rag_tool import RagTool
127
127
  from versionhq.tool.gpt.web_search import GPTToolWebSearch
128
128
  from versionhq.tool.gpt.file_search import GPTToolFileSearch
129
- from versionhq.tool.gpt.cup import GPTToolCUP
129
+ from versionhq.tool.gpt.cua import GPTToolCUA
130
130
 
131
131
  if not self.tools:
132
132
  return self
@@ -134,7 +134,7 @@ class Agent(BaseModel):
134
134
  tool_list = []
135
135
  for item in self.tools:
136
136
  match item:
137
- case RagTool() | BaseTool() | GPTToolCUP() | GPTToolFileSearch() | GPTToolWebSearch():
137
+ case RagTool() | BaseTool() | GPTToolCUA() | GPTToolFileSearch() | GPTToolWebSearch():
138
138
  tool_list.append(item)
139
139
 
140
140
  case Tool():
@@ -433,7 +433,7 @@ class Agent(BaseModel):
433
433
  from versionhq.tool.rag_tool import RagTool
434
434
  from versionhq.tool.gpt.web_search import GPTToolWebSearch
435
435
  from versionhq.tool.gpt.file_search import GPTToolFileSearch
436
- from versionhq.tool.gpt.cup import GPTToolCUP
436
+ from versionhq.tool.gpt.cua import GPTToolCUA
437
437
 
438
438
  all_tools = []
439
439
  if task: all_tools = task.tools + self.tools if task.can_use_agent_tools else task.tools
@@ -446,7 +446,7 @@ class Agent(BaseModel):
446
446
  case RagTool():
447
447
  rag_tools.append(item)
448
448
 
449
- case GPTToolCUP() | GPTToolFileSearch() | GPTToolWebSearch():
449
+ case GPTToolCUA() | GPTToolFileSearch() | GPTToolWebSearch():
450
450
  gpt_tools.append(item)
451
451
 
452
452
  case Tool() | BaseTool() | ToolSet():
versionhq/task/model.py CHANGED
@@ -18,7 +18,7 @@ from versionhq.tool.model import Tool, ToolSet, BaseTool
18
18
  from versionhq.tool.rag_tool import RagTool
19
19
  from versionhq.tool.gpt.web_search import GPTToolWebSearch
20
20
  from versionhq.tool.gpt.file_search import GPTToolFileSearch
21
- from versionhq.tool.gpt.cup import GPTToolCUP
21
+ from versionhq.tool.gpt.cua import GPTToolCUA
22
22
  from versionhq._utils import process_config, Logger, UsageMetrics, ErrorType
23
23
 
24
24
 
@@ -374,7 +374,7 @@ class Task(BaseModel):
374
374
  tool_list = []
375
375
  for item in self.tools:
376
376
  match item:
377
- case Tool() | ToolSet() | BaseTool() | RagTool() | GPTToolCUP() | GPTToolFileSearch() | GPTToolWebSearch():
377
+ case Tool() | ToolSet() | BaseTool() | RagTool() | GPTToolCUA() | GPTToolFileSearch() | GPTToolWebSearch():
378
378
  tool_list.append(item)
379
379
  case type(item, callable):
380
380
  tool_list.append(Tool(func=item))
@@ -387,6 +387,8 @@ class Task(BaseModel):
387
387
  tool = RagTool(**item)
388
388
  except:
389
389
  pass
390
+ if tool:
391
+ tool_list.append(tool)
390
392
  case _:
391
393
  pass
392
394
  self.tools = tool_list
@@ -713,7 +715,7 @@ class Task(BaseModel):
713
715
  sig = inspect.signature(self.callback)
714
716
  valid_keys = [param.name for param in sig.parameters.values() if param.kind == param.POSITIONAL_OR_KEYWORD]
715
717
  valid_kwargs = { k: kwargs[k] if k in kwargs else None for k in valid_keys }
716
- callback_res = self.callback(**valid_kwargs)
718
+ callback_res = self.callback(**valid_kwargs, **task_output.json_dict )
717
719
  task_output.callback_output = callback_res
718
720
 
719
721
  end_dt = datetime.datetime.now()
@@ -7,14 +7,14 @@ class GPTSizeEnum(str, Enum):
7
7
  HIGH = "high"
8
8
 
9
9
 
10
- class GPTCUPEnvironmentEnum(str, Enum):
10
+ class GPTCUAEnvironmentEnum(str, Enum):
11
11
  BROWSER = "browser"
12
12
  MAC = "mac"
13
13
  WINDOWS = "windows"
14
14
  UNBUNTU = "ubuntu"
15
15
 
16
16
 
17
- class GPTCUPTypeEnum(str, Enum):
17
+ class GPTCUATypeEnum(str, Enum):
18
18
  COMPUTER_CALL_OUTPUT = "computer_call_output"
19
19
  COMPUTER_USE_PREVIEW = "computer_use_preview"
20
20
 
@@ -0,0 +1,295 @@
1
+ import datetime
2
+ import time
3
+ from typing import List, Dict, Any, Tuple
4
+
5
+ from versionhq._utils import convert_img_url
6
+ from versionhq.tool.gpt import openai_client
7
+ from versionhq.tool.gpt._enum import GPTCUAEnvironmentEnum, GPTCUATypeEnum, GPTSizeEnum
8
+ from versionhq._utils import is_valid_enum, UsageMetrics, ErrorType, Logger, is_valid_url
9
+
10
+
11
+ allowed_browsers = ['webkit', 'chromium', 'firefox']
12
+
13
+
14
+ class CUAToolSchema:
15
+ type: str = GPTCUATypeEnum.COMPUTER_USE_PREVIEW.value
16
+ display_width: int = 1024
17
+ display_height: int = 768
18
+ environment: str = GPTCUAEnvironmentEnum.BROWSER.value
19
+
20
+ def __init__(
21
+ self,
22
+ type: str | GPTCUATypeEnum = None,
23
+ display_width: int = None,
24
+ display_height: int = None,
25
+ environment: str | GPTCUAEnvironmentEnum = None
26
+ ):
27
+ self.display_height = display_height if display_height else self.display_height
28
+ self.display_width = display_width if display_width else self.display_width
29
+
30
+ if type and is_valid_enum(enum=GPTCUATypeEnum, val=type):
31
+ self.type = type.value if isinstance(type, GPTCUATypeEnum) else type
32
+
33
+ if environment and is_valid_enum(enum=GPTCUAEnvironmentEnum, val=environment):
34
+ self.environment = environment.value if isinstance(environment, GPTCUAEnvironmentEnum) else environment
35
+
36
+ self.environment = environment if environment else self.environment
37
+
38
+
39
+ @property
40
+ def schema(self) -> Dict[str, Any]:
41
+ return {
42
+ "type": self.type if isinstance(self.type, str) else self.type.value,
43
+ "display_width": self.display_width,
44
+ "display_height": self.display_height,
45
+ "environment": self.environment if isinstance(self.environment, str) else self.environment.value,
46
+ }
47
+
48
+
49
+ class GPTToolCUA:
50
+ model: str = "computer-use-preview"
51
+ tools: List[CUAToolSchema] = list()
52
+ user_prompt: str = None
53
+ img_url: str = None
54
+ web_url: str = "https://www.google.com"
55
+ browser: str = "firefox"
56
+ reasoning_effort: str = GPTSizeEnum.MEDIUM.value
57
+ truncation: str = "auto"
58
+
59
+ _response_ids: List[str] = list()
60
+ _call_ids: List[str] = list()
61
+ _usage: UsageMetrics = UsageMetrics()
62
+ _logger: Logger = Logger(info_file_save=True, filename="cua-task-{}".format(str(datetime.datetime.now().timestamp())) + ".png")
63
+
64
+
65
+ def __init__(
66
+ self,
67
+ user_prompt: str,
68
+ tools: List[CUAToolSchema] | CUAToolSchema = None,
69
+ img_url: str = None,
70
+ web_url: str = "https://www.google.com",
71
+ browser: str = "chromium",
72
+ reasoning_effort: GPTSizeEnum | str = None,
73
+ truncation: str = None,
74
+ _usage: UsageMetrics = UsageMetrics()
75
+ ):
76
+ self.user_prompt = user_prompt
77
+ self.web_url = web_url if is_valid_url(web_url) else "https://www.google.com"
78
+ self.browser = browser if browser in allowed_browsers else 'chromium'
79
+ self.truncation = truncation if truncation else self.truncation
80
+ self._usage = _usage
81
+ self._response_ids = list()
82
+ self._call_ids = list()
83
+
84
+ if img_url:
85
+ img_url = convert_img_url(img_url)
86
+ self.img_url = img_url
87
+
88
+ if reasoning_effort and is_valid_enum(enum=GPTSizeEnum, val=reasoning_effort):
89
+ self.reasoning_effort = reasoning_effort.value if isinstance(reasoning_effort, GPTSizeEnum) else reasoning_effort
90
+
91
+ if tools:
92
+ match tools:
93
+ case list():
94
+ if self.tools:
95
+ self.tools.extend(tools)
96
+ else:
97
+ self.tools = tools
98
+ case CUAToolSchema():
99
+ if self.tools:
100
+ self.tools.append(tools)
101
+ else:
102
+ self.tools = [tools]
103
+ case _:
104
+ pass
105
+
106
+
107
+ def _take_screenshot(self, page: Any = None, path: str = None) -> Tuple[str | None, str | None]:
108
+ import base64
109
+ if not page:
110
+ return None, None
111
+
112
+ path = path if path else "screenshot.png"
113
+ screenshot_bytes = page.screenshot()
114
+ screenshot_base64 = base64.b64encode(screenshot_bytes).decode("utf-8")
115
+ self._logger.log(message=f"Action: screenshot", level="info", color="blue")
116
+ return screenshot_bytes, screenshot_base64
117
+
118
+
119
+ def _handle_model_action(self, page: Any, action: Any, action_type: str = None) -> bool:
120
+ """Creates a page object and performs actions."""
121
+
122
+ action_type = action_type if action_type else action.type
123
+ start_dt = datetime.datetime.now()
124
+
125
+ try:
126
+ match action_type:
127
+ case "click":
128
+ x, y = action.x, action.y
129
+ button = action.button
130
+ self._logger.log(message=f"Action: click at ({x}, {y}) with button '{button}'", level="info", color="blue")
131
+ if button != "left" and button != "right":
132
+ button = "left"
133
+ page.mouse.click(x, y, button=button)
134
+
135
+ case "scroll":
136
+ x, y = action.x, action.y
137
+ scroll_x, scroll_y = action.scroll_x, action.scroll_y
138
+ self._logger.log(message=f"Action: scroll at ({x}, {y}) with offsets (scroll_x={scroll_x}, scroll_y={scroll_y})", level="info", color="blue")
139
+ page.mouse.move(x, y)
140
+ page.evaluate(f"window.scrollBy({scroll_x}, {scroll_y})")
141
+
142
+ case "keypress":
143
+ keys = action.keys
144
+ for k in keys:
145
+ self._logger.log(message=f"Action: keypress '{k}'", level="info", color="blue")
146
+ if k.lower() == "enter":
147
+ page.keyboard.press("Enter")
148
+ elif k.lower() == "space":
149
+ page.keyboard.press(" ")
150
+ else:
151
+ page.keyboard.press(k)
152
+
153
+ case "type":
154
+ text = action.text
155
+ self._logger.log(message=f"Action: type text: {text}", level="info", color="blue")
156
+ page.keyboard.type(text)
157
+
158
+ case "wait":
159
+ self._logger.log(message=f"Action: wait", level="info", color="blue")
160
+ time.sleep(2)
161
+
162
+ case "screenshot":
163
+ pass
164
+
165
+ case _:
166
+ self._logger.log(message=f"Unrecognized action: {action}", level="warning", color="yellow")
167
+
168
+ except Exception as e:
169
+ self._usage.record_errors(type=ErrorType.API)
170
+ self._logger.log(message=f"Error handling action {action}: {e}", level="error", color="red")
171
+
172
+ end_dt = datetime.datetime.now()
173
+ self._usage.record_latency(start_dt=start_dt, end_dt=end_dt)
174
+ return bool(self._usage.total_errors)
175
+
176
+
177
+ def run(self, screenshot: str = None) -> Tuple[Dict[str, Any], None, UsageMetrics]:
178
+ raw_res = dict()
179
+ usage = self._usage if self._usage else UsageMetrics()
180
+ start_dt = datetime.datetime.now()
181
+
182
+ try:
183
+ schema = self.schema
184
+ if screenshot and "output" in schema["input"][0]:
185
+ output_image_url = schema["input"][0]["output"]["image_url"].replace("SCREENSHOT", str(screenshot))
186
+ schema["input"][0]["output"]["image_url"] = output_image_url
187
+
188
+ res = openai_client.responses.create(**schema)
189
+ if not res:
190
+ usage.record_errors(ErrorType.TOOL)
191
+ else:
192
+ for item in res.output:
193
+ match item.type:
194
+ case "reasoning":
195
+ raw_res.update(dict(reasoning=item.summary[0].text))
196
+ if item.id and item.id.startwith('rs'):
197
+ self._response_ids.append(item.id)
198
+ case "computer_call":
199
+ raw_res.update(dict(action=item.action))
200
+ # self._response_ids.append(item.id)
201
+ self._call_ids.append(item.call_id)
202
+ case _:
203
+ pass
204
+ usage.record_token_usage(**res.usage.__dict__)
205
+
206
+ except Exception as e:
207
+ self._logger.log(message=f"Failed to run: {str(e)}", color="red", level="error")
208
+ usage.record_errors(ErrorType.TOOL)
209
+
210
+ end_dt = datetime.datetime.now()
211
+ usage.record_latency(start_dt=start_dt, end_dt=end_dt)
212
+ return raw_res, None, usage
213
+
214
+
215
+ def invoke_playwright(self) -> Tuple[Dict[str, Any], None, UsageMetrics]:
216
+ """Handles computer use loop. Ref. OpenAI official website."""
217
+
218
+ from playwright.sync_api import sync_playwright
219
+
220
+ self._logger.log(message="Start the operation.", level="info", color="blue")
221
+
222
+ try:
223
+ with sync_playwright() as p:
224
+ b = p.firefox if self.browser == "firefox" else p.webkit if self.browser == "webkit" else p.chromium
225
+ browser = b.launch(headless=True)
226
+ page = browser.new_page()
227
+ if not browser or not page:
228
+ return None, None, None
229
+
230
+ page.goto(self.web_url)
231
+ res, _, usage = self.run()
232
+ self._usage = usage
233
+ actions = [v for k, v in res.items() if k =="action"] if res else []
234
+ action = actions[0] if actions else None
235
+ start_dt = datetime.datetime.now()
236
+
237
+ if action:
238
+ while True:
239
+ self._handle_model_action(page=page, action=action)
240
+ _, screenshot_base64 = self._take_screenshot(page=page)
241
+ res, _, usage = self.run(screenshot=screenshot_base64)
242
+ self._usage.agggregate(metrics=usage)
243
+ if not res:
244
+ usage.record_errors(type=ErrorType.API)
245
+ break
246
+
247
+ actions = [v for k, v in res.items() if k =="action"] if res else []
248
+ action = actions[0] if actions else None
249
+ if not action:
250
+ break
251
+ else:
252
+ self._usage.record_errors(type=ErrorType.TOOL)
253
+
254
+ except Exception as e:
255
+ self._logger.log(message=f"Failed to execute. {str(e)}", color="red", level="error")
256
+
257
+ end_dt = datetime.datetime.now()
258
+ self._usage.record_latency(start_dt=start_dt, end_dt=end_dt)
259
+ # browser.close()
260
+ return res, _, self._usage
261
+
262
+
263
+ @property
264
+ def schema(self) -> Dict[str, Any]:
265
+ """Formats args schema for CUA calling."""
266
+
267
+ tool_schema = [item.schema for item in self.tools]
268
+ schema = dict()
269
+ inputs = list()
270
+ previous_response_id = self._response_ids[-1] if self._response_ids and self._response_ids[-1].startswith("rs") else None
271
+
272
+ if self._call_ids:
273
+ inputs = [
274
+ {
275
+ "call_id": self._call_ids[-1],
276
+ "type": "computer_call_output",
277
+ "output": { "type": "input_image", "image_url": f"data:image/png;base64,SCREENSHOT"}
278
+ }
279
+ ]
280
+ schema = dict(
281
+ model=self.model,
282
+ previous_response_id=previous_response_id,
283
+ tools=tool_schema,
284
+ input=inputs,
285
+ truncation=self.truncation
286
+ )
287
+
288
+ else:
289
+ img_url = convert_img_url(self.img_url) if self.img_url else None
290
+ input = [{ "role": "user", "content": self.user_prompt } ]
291
+ if img_url:
292
+ input.append({"type": "input_image", "image_url": f"data:image/png;base64,{img_url}"})
293
+ schema = dict(model=self.model, tools=tool_schema, input=input, reasoning={ "effort": self.reasoning_effort}, truncation=self.truncation)
294
+
295
+ return schema
@@ -1,3 +1,4 @@
1
+ import datetime
1
2
  from typing import List, Dict, Any, Optional, Tuple
2
3
 
3
4
  from versionhq.tool.gpt import openai_client
@@ -87,6 +88,7 @@ class GPTToolFileSearch:
87
88
  max_num_results: int = 2
88
89
  include: List[str] = ["output[*].file_search_call.search_results"]
89
90
  filters: Optional[FilterSchema] = None
91
+ _usage: UsageMetrics = UsageMetrics()
90
92
 
91
93
  def __init__(
92
94
  self,
@@ -119,7 +121,8 @@ class GPTToolFileSearch:
119
121
  def run(self) -> Tuple[str, List[Dict[str, Any]], UsageMetrics] | None:
120
122
  raw_res = ""
121
123
  annotations = list()
122
- usage = UsageMetrics()
124
+ usage = self._usage if self._usage else UsageMetrics()
125
+ start_dt = datetime.datetime.now()
123
126
 
124
127
  try:
125
128
  res = openai_client.responses.create(**self.schema)
@@ -130,10 +133,14 @@ class GPTToolFileSearch:
130
133
  annotations = [{ "index": item.index, "file_id": item.file_id, "filename": item.filename }
131
134
  for item in res.output[1].content[0].annotations]
132
135
  usage.record_token_usage(**res.usage.__dict__)
133
- return raw_res, annotations, usage
136
+
134
137
  except:
135
138
  usage.record_errors(ErrorType.TOOL)
136
- return raw_res, annotations, usage
139
+
140
+ end_dt = datetime.datetime.now()
141
+ usage.record_latency(start_dt=start_dt, end_dt=end_dt)
142
+ self._usage = usage
143
+ return raw_res, annotations, usage
137
144
 
138
145
 
139
146
  @property
@@ -1,3 +1,4 @@
1
+ import datetime
1
2
  from typing import Dict, Any, Optional, Tuple, List
2
3
 
3
4
  from versionhq.tool.gpt import openai_client
@@ -16,6 +17,7 @@ class GPTToolWebSearch:
16
17
  region: str = None # "London"
17
18
  search_content_size: str = GPTSizeEnum.MEDIUM.value
18
19
  _user_location: Optional[Dict[str, str]] = None
20
+ _usage: UsageMetrics = UsageMetrics()
19
21
 
20
22
 
21
23
  def __init__(
@@ -52,20 +54,25 @@ class GPTToolWebSearch:
52
54
 
53
55
  raw_res = ""
54
56
  annotations = list()
55
- usage = UsageMetrics()
57
+ usage = self._usage if self._usage else UsageMetrics()
58
+ start_dt = datetime.datetime.now()
56
59
 
57
60
  try:
58
61
  res = openai_client.responses.create(**self.schema)
59
62
  if not res:
60
63
  usage.record_errors(ErrorType.TOOL)
61
64
  else:
62
- raw_res = res.output[1].content[0].text
63
- annotations = [{ "title": item.title, "url": item.url } for item in res.output[1].content[0].annotations]
64
- usage.record_token_usage(**res.usage.__dict__)
65
- return raw_res, annotations, usage
65
+ content = res.output[0].content[0] if len(res.output) == 1 else res.output[1].content[0]
66
+ if content:
67
+ raw_res = content.text
68
+ annotations = [{ "title": item.title, "url": item.url } for item in content.annotations] if content.annotations else []
69
+ usage.record_token_usage(**res.usage.__dict__)
66
70
  except:
67
71
  usage.record_errors(ErrorType.TOOL)
68
- return raw_res, annotations, usage
72
+ end_dt = datetime.datetime.now()
73
+ usage.record_latency(start_dt=start_dt, end_dt=end_dt)
74
+ self._usage = usage
75
+ return raw_res, annotations, usage
69
76
 
70
77
 
71
78
  @property
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: versionhq
3
- Version: 1.2.4.7
3
+ Version: 1.2.4.8
4
4
  Summary: Autonomous agent networks for task automation with multi-step reasoning.
5
5
  Author-email: Kuriko Iwai <kuriko@versi0n.io>
6
6
  License: MIT License
@@ -77,6 +77,7 @@ Requires-Dist: pygraphviz>=1.14; extra == "pygraphviz"
77
77
  Provides-Extra: tools
78
78
  Requires-Dist: html2text>=2024.2.26; extra == "tools"
79
79
  Requires-Dist: sec-api>=1.0.28; extra == "tools"
80
+ Requires-Dist: pytest-playwright>=0.7.0; extra == "tools"
80
81
  Provides-Extra: torch
81
82
  Requires-Dist: torch>=2.6.0; extra == "torch"
82
83
  Requires-Dist: torchvision>=0.21.0; extra == "torch"
@@ -290,8 +291,11 @@ class CustomOutput(BaseModel):
290
291
  test1: str
291
292
  test2: list[str]
292
293
 
293
- def dummy_func(message: str, test1: str, test2: list[str]) -> str:
294
- return f"""{message}: {test1}, {", ".join(test2)}"""
294
+ def dummy_func(message: str, **kwargs) -> str:
295
+ test1 = kwargs["test1"] if kwargs and "test1" in kwargs else ""
296
+ test2 = kwargs["test2"] if kwargs and "test2" in kwargs else ""
297
+ if test1 and test2:
298
+ return f"""{message}: {test1}, {", ".join(test2)}"""
295
299
 
296
300
  task = vhq.Task(
297
301
  description="Amazing task",
@@ -1,4 +1,4 @@
1
- versionhq/__init__.py,sha256=92oz-3IZ_FZAsIUPMZGHwCtcFDQ7dd1kJ79v_1Cz1PY,3333
1
+ versionhq/__init__.py,sha256=oR5US-k9B6iSSPXIrHW2B0pFggJ2iav8hQ8vzR46gy4,3333
2
2
  versionhq/_prompt/auto_feedback.py,sha256=bbj37yTa11lRHpx-sV_Wmpb4dVnDBB7_v8ageUobHXY,3780
3
3
  versionhq/_prompt/constants.py,sha256=DOwUFnVVObEFqgnaMCDnW8fnw1oPMgS8JAqOiTuqleI,932
4
4
  versionhq/_prompt/model.py,sha256=wJlDM9yzrqlXWxyw4HkYQzPii2MPfqkgTF3qhXoJN2M,8038
@@ -8,13 +8,13 @@ versionhq/_utils/i18n.py,sha256=TwA_PnYfDLA6VqlUDPuybdV9lgi3Frh_ASsb_X8jJo8,1483
8
8
  versionhq/_utils/is_valid_enum.py,sha256=vGGIuvhDnFU2fUyyFxJyjw-NfByK0vfFAu1ShaHBeZE,720
9
9
  versionhq/_utils/is_valid_url.py,sha256=m8Mswvb-90FJtx1Heq6hPFDbwGgrv_R3wSbZQmEPM9Q,379
10
10
  versionhq/_utils/llm_as_a_judge.py,sha256=2XcuFqEVb6P6vHxWQNv8XM2b4APyvEir5QI9TPgHt_U,2353
11
- versionhq/_utils/logger.py,sha256=iHxGjm3BvUo5dHKLU88_pc0Z45wzSHOjyJGQkb7OADk,3255
11
+ versionhq/_utils/logger.py,sha256=Y8id03u2ME7CDQl-HuS6M_LL8Q5SeMfoGPxp9mj9CGo,3249
12
12
  versionhq/_utils/process_config.py,sha256=YTGY_erW335RfceQfzS18YAqq-AAb-iSvKSjN7noD2E,782
13
13
  versionhq/_utils/usage_metrics.py,sha256=gDK6fZgT1njX4iPIPFapWxfxIiz-zZYv72p0u6M055U,3387
14
14
  versionhq/_utils/vars.py,sha256=bZ5Dx_bFKlt3hi4-NNGXqdk7B23If_WaTIju2fiTyPQ,57
15
15
  versionhq/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  versionhq/agent/inhouse_agents.py,sha256=D2WAiXCYsnQK3_Fe7CbbtvXsHWOaN6vde6m_QoW7fH4,2629
17
- versionhq/agent/model.py,sha256=kEsJri5RWSAzQ4jNYhS3WYSJTNyTT1huqyTlqjSK62E,26969
17
+ versionhq/agent/model.py,sha256=HW_-k9wBhHpo1mtvDW6mGV2X20qQ7_ds4ZBubpTf_JU,26969
18
18
  versionhq/agent/parser.py,sha256=riG0dkdQCxH7uJ0AbdVdg7WvL0BXhUgJht0VtQvxJBc,4082
19
19
  versionhq/agent/rpm_controller.py,sha256=grezIxyBci_lDlwAlgWFRyR5KOocXeOhYkgN02dNFNE,2360
20
20
  versionhq/agent/TEMPLATES/Backstory.py,sha256=dkfuATUQ2g2WoUKkmgAIch-RB--bektGoQaUlsDOn0g,529
@@ -53,7 +53,7 @@ versionhq/storage/utils.py,sha256=r5ghA_ktdR2IuzlzKqZYCjsNxztEMzyhWLneA4cFuWY,74
53
53
  versionhq/task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  versionhq/task/evaluation.py,sha256=9jFOmjP-yy1vxRn781KmpdQ_d4J_ZA1UX_21Q3m-iuE,4122
55
55
  versionhq/task/formatter.py,sha256=N8Kmk9vtrMtBdgJ8J7RmlKNMdZWSmV8O1bDexmCWgU0,643
56
- versionhq/task/model.py,sha256=lTpog4ERVlcl95ku-ZCVbi7htT7hnI-YGM_JFZJ27k8,29462
56
+ versionhq/task/model.py,sha256=-RZKeplcRSwfQzLj4lh2TyTkgxyPaiaujXKjsXDol54,29572
57
57
  versionhq/task/structured_response.py,sha256=tqOHpch8CVmMj0aZXjdDWtPNcVmBW8DVZnBvPBwS4PM,5053
58
58
  versionhq/task/TEMPLATES/Description.py,sha256=hKhpbz0ztbkUMXz9KiL-P40fis9OB5ICOdL9jCtgAhU,864
59
59
  versionhq/task_graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -70,12 +70,12 @@ versionhq/tool/composio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
70
70
  versionhq/tool/composio/model.py,sha256=GIFKso_e_4a3BdaulqU_i6Y9JFAExNBjzHUHR_zZeSI,8577
71
71
  versionhq/tool/composio/params.py,sha256=FvBuEXsOQUYnN7RTFxT20kAkiEYkxWKkiVtgpqOzKZQ,1843
72
72
  versionhq/tool/gpt/__init__.py,sha256=A6xCuf_GUBs7wfx904J_Vd2t1GJCcf0lMKOL7MbZce4,160
73
- versionhq/tool/gpt/_enum.py,sha256=fw31aYeQBY8vfRwzjvwa1IVhhpAAQt9m1jqQTjTBpLk,500
74
- versionhq/tool/gpt/cup.py,sha256=Vz7VmTQV0IvUZcyN9znH7d7XUvLzm2SlSXJ5NoJFk3Q,5048
75
- versionhq/tool/gpt/file_search.py,sha256=CoPwNNoGF4U-0OuUMixqjdt5YoO0tqWbdbR_7UE-dMk,5597
76
- versionhq/tool/gpt/web_search.py,sha256=NoeW7m_YxhUp8NanTjBt3GX6nAU6G8bi_jfpLfWyx90,3127
77
- versionhq-1.2.4.7.dist-info/LICENSE,sha256=cRoGGdM73IiDs6nDWKqPlgSv7aR4n-qBXYnJlCMHCeE,1082
78
- versionhq-1.2.4.7.dist-info/METADATA,sha256=7yovXpbFgfbIoPKXkVUUI5XvxkqJz6cxSJ6BGAkCFO4,21146
79
- versionhq-1.2.4.7.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
80
- versionhq-1.2.4.7.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
81
- versionhq-1.2.4.7.dist-info/RECORD,,
73
+ versionhq/tool/gpt/_enum.py,sha256=VaONDFZJNVe30Wf3Pl9s0XvxP_Xxqv3RNFcnqyigGFk,500
74
+ versionhq/tool/gpt/cua.py,sha256=5yrgz_fc3IH_uB70J51wmRBWkfH53Qx-a29nmwWyOcs,12078
75
+ versionhq/tool/gpt/file_search.py,sha256=r5JVlf-epKB8DDXyrzlkezguHUMir0JW-77LUHoy-w8,5813
76
+ versionhq/tool/gpt/web_search.py,sha256=bpqEQopbq9KtqQ_0W7QAAJ5TyoKGiVM94-SMp5oqNFE,3483
77
+ versionhq-1.2.4.8.dist-info/LICENSE,sha256=cRoGGdM73IiDs6nDWKqPlgSv7aR4n-qBXYnJlCMHCeE,1082
78
+ versionhq-1.2.4.8.dist-info/METADATA,sha256=Gix43l0cnBFyfpXCDSg9R7Jm8FhrU2Te8jtdhg7sFck,21344
79
+ versionhq-1.2.4.8.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
80
+ versionhq-1.2.4.8.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
81
+ versionhq-1.2.4.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (76.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
versionhq/tool/gpt/cup.py DELETED
@@ -1,145 +0,0 @@
1
- from typing import List, Dict, Any
2
-
3
- from versionhq._utils import convert_img_url
4
- from versionhq.tool.gpt import openai_client
5
- from versionhq.tool.gpt._enum import GPTCUPEnvironmentEnum, GPTCUPTypeEnum, GPTSizeEnum
6
- from versionhq._utils import is_valid_enum, UsageMetrics, ErrorType
7
-
8
-
9
- class CUPToolSchema:
10
- type: str = GPTCUPTypeEnum.COMPUTER_USE_PREVIEW.value
11
- display_width: int = 1024
12
- display_height: int = 768
13
- environment: str = GPTCUPEnvironmentEnum.BROWSER.value
14
-
15
- def __init__(
16
- self,
17
- type: str | GPTCUPTypeEnum = None,
18
- display_width: int = None,
19
- display_height: int = None,
20
- environment: str | GPTCUPEnvironmentEnum = None
21
- ):
22
- self.display_height = display_height if display_height else self.display_height
23
- self.display_width = display_width if display_width else self.display_width
24
-
25
- if type and is_valid_enum(enum=GPTCUPTypeEnum, val=type):
26
- self.type = type.value if isinstance(type, GPTCUPTypeEnum) else type
27
-
28
- if environment and is_valid_enum(enum=GPTCUPEnvironmentEnum, val=environment):
29
- self.environment = environment.value if isinstance(environment, GPTCUPEnvironmentEnum) else environment
30
-
31
- self.environment = environment if environment else self.environment
32
-
33
-
34
- @property
35
- def schema(self) -> Dict[str, Any]:
36
- return {
37
- "type": self.type if isinstance(self.type, str) else self.type.value,
38
- "display_width": self.display_width,
39
- "display_height": self.display_height,
40
- "environment": self.environment if isinstance(self.environment, str) else self.environment.value,
41
- }
42
-
43
-
44
- class GPTToolCUP:
45
- model: str = "computer-use-preview"
46
- tools: List[CUPToolSchema] = list()
47
- user_prompt: str = None
48
- img_url: str = None
49
- reasoning_effort: str = GPTSizeEnum.MEDIUM.value
50
- truncation: str = "auto"
51
-
52
- def __init__(
53
- self,
54
- user_prompt: str,
55
- tools: List[CUPToolSchema] | CUPToolSchema = None,
56
- img_url: str = None,
57
- reasoning_effort: GPTSizeEnum | str = None,
58
- truncation: str = None
59
- ):
60
- self.user_prompt = user_prompt
61
- self.truncation = truncation if truncation else self.truncation
62
-
63
- if img_url:
64
- img_url = convert_img_url(img_url)
65
- self.img_url = img_url
66
-
67
- if reasoning_effort and is_valid_enum(enum=GPTSizeEnum, val=reasoning_effort):
68
- self.reasoning_effort = reasoning_effort.value if isinstance(reasoning_effort, GPTSizeEnum) else reasoning_effort
69
-
70
- if tools:
71
- match tools:
72
- case list():
73
- if self.tools:
74
- self.tools.extend(tools)
75
- else:
76
- self.tools = tools
77
- case CUPToolSchema():
78
- if self.tools:
79
- self.tools.append(tools)
80
- else:
81
- self.tools = [tools]
82
- case _:
83
- pass
84
-
85
- def run(self):
86
- raw_res = ""
87
- usage = UsageMetrics()
88
-
89
- try:
90
- res = openai_client.responses.create(**self.schema)
91
- if not res:
92
- usage.record_errors(ErrorType.TOOL)
93
- else:
94
- raw_res = res.output[1].summary[0].text
95
- usage.record_token_usage(**res.usage.__dict__)
96
- return raw_res, None, usage
97
- except:
98
- usage.record_errors(ErrorType.TOOL)
99
- return raw_res, None, usage
100
-
101
-
102
- @property
103
- def schema(self) -> Dict[str, Any]:
104
- img_url = convert_img_url(self.img_url) if self.img_url else None
105
- inputs = [{ "role": "user", "content": self.user_prompt } ]
106
-
107
- if img_url:
108
- inputs.append({"type": "input_image", "image_url": f"data:image/png;base64,{img_url}"})
109
-
110
- tool_schema = [item.schema for item in self.tools]
111
- schema = dict(model=self.model, tools=tool_schema, input=inputs, reasoning={ "effort": self.reasoning_effort}, truncation=self.truncation)
112
- return schema
113
-
114
-
115
- # "output": [
116
- # {
117
- # "type": "reasoning",
118
- # "id": "rs_67cb...",
119
- # "summary": [
120
- # {
121
- # "type": "summary_text",
122
- # "text": "Exploring 'File' menu option."
123
- # }
124
- # ]
125
- # },
126
- # {
127
- # "type": "computer_call",
128
- # "id": "cu_67cb...",
129
- # "call_id": "call_nEJ...",
130
- # "action": {
131
- # "type": "click",
132
- # "button": "left",
133
- # "x": 135,
134
- # "y": 193
135
- # },
136
- # "pending_safety_checks": [
137
- # {
138
- # "id": "cu_sc_67cb...",
139
- # "code": "malicious_instructions",
140
- # "message": "We've detected instructions that may cause your application to perform malicious or unauthorized actions. Please acknowledge this warning if you'd like to proceed."
141
- # }
142
- # ],
143
- # "status": "completed"
144
- # }
145
- # ]