versionhq 1.2.1.22__py3-none-any.whl → 1.2.2.0__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.
@@ -4,15 +4,18 @@ from enum import Enum
4
4
  from concurrent.futures import Future
5
5
  from hashlib import md5
6
6
  from typing import Any, Dict, List, Callable, Optional, Tuple
7
+ from typing_extensions import Self
8
+
7
9
  from pydantic import UUID4, BaseModel, Field, PrivateAttr, field_validator, model_validator
8
10
  from pydantic._internal._generate_schema import GenerateSchema
9
11
  from pydantic_core import PydanticCustomError, core_schema
10
12
 
13
+
11
14
  from versionhq.agent.model import Agent
12
15
  from versionhq.task.model import Task, TaskOutput, TaskExecutionType, ResponseField
13
- from versionhq.task.formatter import create_raw_outputs
16
+ from versionhq.task_graph.model import TaskGraph, Node, Edge, TaskStatus, DependencyType
14
17
  from versionhq._utils.logger import Logger
15
- from versionhq._utils.usage_metrics import UsageMetrics
18
+ # from versionhq.recording.usage_metrics import UsageMetrics
16
19
 
17
20
 
18
21
  initial_match_type = GenerateSchema.match_type
@@ -40,36 +43,9 @@ class TaskHandlingProcess(str, Enum):
40
43
  A class representing task handling processes to tackle multiple tasks.
41
44
  When the agent network has multiple tasks that connect with edges, follow the edge conditions.
42
45
  """
43
- SEQUENT = 1
44
- HIERARCHY = 2
45
- CONSENSUAL = 3 # either from managers or peers or (human) - most likely controlled by edge
46
-
47
-
48
- class NetworkOutput(TaskOutput):
49
- """
50
- A class to store output from the network, inherited from TaskOutput class.
51
- """
52
-
53
- network_id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True, description="store the network ID as an identifier that generate the output")
54
- task_description: str = Field(default=None, description="store initial request (task description) from the client")
55
- task_outputs: list[TaskOutput] = Field(default=list, description="store TaskOutput objects of all tasks that the network has executed")
56
- # token_usage: UsageMetrics = Field(default=dict, description="processed token summary")
57
-
58
- def return_all_task_outputs(self) -> List[Dict[str, Any]]:
59
- res = [output.json_dict for output in self.task_outputs]
60
- return res
61
-
62
- def __str__(self):
63
- return (str(self.pydantic) if self.pydantic else str(self.json_dict) if self.json_dict else self.raw)
64
-
65
- def __getitem__(self, key):
66
- if self.pydantic and hasattr(self.pydantic, key):
67
- return getattr(self.pydantic, key)
68
- elif self.json_dict and key in self.json_dict:
69
- return self.json_dict[key]
70
- else:
71
- raise KeyError(f"Key '{key}' not found in the output.")
72
-
46
+ HIERARCHY = 1
47
+ SEQUENTIAL = 2
48
+ CONSENSUAL = 3 # either from manager class agents from diff network or human. need to define a trigger
73
49
 
74
50
 
75
51
  class Member(BaseModel):
@@ -88,10 +64,7 @@ class Member(BaseModel):
88
64
 
89
65
 
90
66
  class AgentNetwork(BaseModel):
91
- """
92
- A class to store a agent network with agent members and their tasks.
93
- Tasks can be 1. multiple individual tasks, 2. multiple dependant tasks connected via TaskGraph, and 3. hybrid.
94
- """
67
+ """A Pydantic class to store an agent network with agent members and tasks."""
95
68
 
96
69
  __hash__ = object.__hash__
97
70
  _execution_span: Any = PrivateAttr()
@@ -103,27 +76,21 @@ class AgentNetwork(BaseModel):
103
76
  formation: Optional[Formation] = Field(default=None)
104
77
  should_reform: bool = Field(default=False, description="True if task exe. failed or eval scores below threshold")
105
78
 
106
- # formation planning
107
- network_tasks: Optional[List[Task]] = Field(default_factory=list, description="tasks without dedicated agents")
79
+ network_tasks: Optional[List[Task]] = Field(default_factory=list, description="tasks without dedicated agents - network's common tasks")
108
80
 
109
81
  # task execution rules
110
- prompt_file: str = Field(default="", description="absolute path to the prompt json file")
111
- process: TaskHandlingProcess = Field(default=TaskHandlingProcess.SEQUENT)
82
+ prompt_file: str = Field(default="", description="absolute file path to the prompt file that stores jsonified prompts")
83
+ process: TaskHandlingProcess = Field(default=TaskHandlingProcess.SEQUENTIAL)
84
+ consent_trigger: Optional[Callable] = Field(default=None, description="returns bool")
112
85
 
113
86
  # callbacks
114
- pre_launch_callbacks: List[Callable[[Optional[Dict[str, Any]]], Optional[Dict[str, Any]]]] = Field(
115
- default_factory=list,
116
- description="list of callback functions to be executed before the network launch. i.e., adjust inputs"
117
- )
118
- post_launch_callbacks: List[Callable[[NetworkOutput], NetworkOutput]] = Field(
119
- default_factory=list,
120
- description="list of callback functions to be executed after the network launch. i.e., store the result in repo"
121
- )
122
- step_callback: Optional[Any] = Field(default=None, description="callback to be executed after each step for all agents execution")
87
+ pre_launch_callbacks: List[Callable[..., Any]]= Field(default_factory=list, description="list of callback funcs called before the network launch")
88
+ post_launch_callbacks: List[Callable[..., Any]] = Field(default_factory=list, description="list of callback funcs called after the network launch")
89
+ step_callback: Optional[Any] = Field(default=None, description="callback to be executed after each step of all agents execution")
123
90
 
124
91
  cache: bool = Field(default=True)
125
92
  execution_logs: List[Dict[str, Any]] = Field(default_factory=list, description="list of execution logs of the tasks handled by members")
126
- usage_metrics: Optional[UsageMetrics] = Field(default=None, description="usage metrics for all the llm executions")
93
+ # usage_metrics: Optional[UsageMetrics] = Field(default=None, description="usage metrics for all the llm executions")
127
94
 
128
95
 
129
96
  def __name__(self) -> str:
@@ -138,6 +105,24 @@ class AgentNetwork(BaseModel):
138
105
  raise PydanticCustomError("may_not_set_field", "The 'id' field cannot be set by the user.", {})
139
106
 
140
107
 
108
+ @model_validator(mode="after")
109
+ def validate_process(self) -> Self:
110
+ if self.process == TaskHandlingProcess.CONSENSUAL and not self.consent_trigger:
111
+ Logger().log(level="error", message="Need to define the consent trigger function that returns bool", color="red")
112
+ raise PydanticCustomError("invalid_process", "Need to define the consent trigger function that returns bool", {})
113
+
114
+ return self
115
+
116
+
117
+ @model_validator(mode="after")
118
+ def set_up_network_for_members(self) -> Self:
119
+ if self.members:
120
+ for member in self.members:
121
+ member.agent.networks.append(self)
122
+
123
+ return self
124
+
125
+
141
126
  @model_validator(mode="after")
142
127
  def assess_tasks(self):
143
128
  """
@@ -181,7 +166,7 @@ class AgentNetwork(BaseModel):
181
166
  """
182
167
  Sequential task processing without any network_tasks require a task-agent pairing.
183
168
  """
184
- if self.process == TaskHandlingProcess.SEQUENT and self.network_tasks is None:
169
+ if self.process == TaskHandlingProcess.SEQUENTIAL and self.network_tasks is None:
185
170
  for task in self.tasks:
186
171
  if not [member.task == task for member in self.members]:
187
172
  Logger().log(level="error", message=f"The following task needs a dedicated agent to be assinged: {task.description}", color="red")
@@ -209,11 +194,8 @@ class AgentNetwork(BaseModel):
209
194
  return self
210
195
 
211
196
 
212
- @staticmethod
213
- def handle_assigning_agents(unassigned_tasks: List[Task]) -> List[Member]:
214
- """
215
- Build an agent and assign it with a task. Return a list of Member connecting the agent created and the task given.
216
- """
197
+ def _generate_agents(self, unassigned_tasks: List[Task]) -> List[Member]:
198
+ """Generates agents as members in the network."""
217
199
 
218
200
  from versionhq.agent.inhouse_agents import vhq_agent_creator
219
201
 
@@ -221,10 +203,7 @@ class AgentNetwork(BaseModel):
221
203
 
222
204
  for unassgined_task in unassigned_tasks:
223
205
  task = Task(
224
- description=f"""
225
- Based on the following task summary, draft a AI agent's role and goal in concise manner.
226
- Task summary: {unassgined_task.summary}
227
- """,
206
+ description=f"Based on the following task summary, draft an agent's role and goal in concise manner. Task summary: {unassgined_task.summary}",
228
207
  response_fields=[
229
208
  ResponseField(title="goal", data_type=str, required=True),
230
209
  ResponseField(title="role", data_type=str, required=True),
@@ -242,187 +221,212 @@ class AgentNetwork(BaseModel):
242
221
  return new_member_list
243
222
 
244
223
 
245
- def _get_responsible_agent(self, task: Task) -> Agent | None:
246
- if task is None:
247
- return None
248
- else:
249
- for member in self.members:
250
- if member.tasks and [item for item in member.tasks if item.id == task.id]:
251
- return member.agent
252
-
253
- return None
254
-
255
-
256
224
  def _assign_tasks(self) -> None:
257
- """
258
- Form a agent network considering given agents and tasks, and update `self.members` field:
259
- 1. Idling managers to take the network tasks.
260
- 2. Idling members to take the remaining tasks starting from the network tasks to member tasks.
261
- 3. Create agents to handle the rest tasks.
262
- """
225
+ """Assigns tasks to member agents."""
263
226
 
264
227
  idling_managers: List[Member] = [member for member in self.members if member.is_idling and member.is_manager == True]
265
228
  idling_members: List[Member] = [member for member in self.members if member.is_idling and member.is_manager == False]
266
- unassigned_tasks: List[Task] = self.network_tasks + self.member_tasks_without_agent if self.network_tasks else self.member_tasks_without_agent
229
+ unassigned_tasks: List[Task] = self.network_tasks + self.unassigned_member_tasks if self.network_tasks else self.unassigned_member_tasks
267
230
  new_members: List[Member] = []
268
231
 
269
- if idling_managers:
270
- idling_managers[0].tasks.extend(unassigned_tasks)
271
-
272
- elif idling_members:
273
- idling_members[0].tasks.extend(unassigned_tasks)
232
+ if not unassigned_tasks:
233
+ return
274
234
 
275
235
  else:
276
- new_members = self.handle_assigning_agents(unassigned_tasks=unassigned_tasks)
277
- if new_members:
278
- self.members += new_members
236
+ if idling_managers:
237
+ idling_managers[0].tasks.extend(unassigned_tasks)
279
238
 
239
+ elif idling_members:
240
+ idling_members[0].tasks.extend(unassigned_tasks)
280
241
 
281
- # task execution
282
- def _process_async_tasks(self, futures: List[Tuple[Task, Future[TaskOutput], int]], was_replayed: bool = False) -> List[TaskOutput]:
283
- """
284
- When we have `Future` tasks, updated task outputs and task execution logs accordingly.
285
- """
242
+ else:
243
+ new_members = self._generate_agents(unassigned_tasks=unassigned_tasks)
244
+ if new_members:
245
+ self.members += new_members
286
246
 
287
- task_outputs: List[TaskOutput] = []
288
247
 
289
- for future_task, future, task_index in futures:
290
- task_output = future.result()
291
- task_outputs.append(task_output)
292
- future_task._store_execution_log(task_index, was_replayed)
248
+ def _get_responsible_agent(self, task: Task) -> Agent | None:
249
+ if not task:
250
+ return None
293
251
 
294
- return task_outputs
252
+ self._assign_tasks()
253
+ for member in self.members:
254
+ if member.tasks and [item for item in member.tasks if item.id == task.id]:
255
+ return member.agent
295
256
 
296
257
 
297
- def _calculate_usage_metrics(self) -> UsageMetrics:
298
- """
299
- Calculate and return the usage metrics that consumed by the agent network.
300
- """
301
- total_usage_metrics = UsageMetrics()
258
+ # task execution
259
+ # def _process_async_tasks(self, futures: List[Tuple[Task, Future[TaskOutput], int]], was_replayed: bool = False) -> List[TaskOutput]:
260
+ # """
261
+ # When we have `Future` tasks, updated task outputs and task execution logs accordingly.
262
+ # """
263
+
264
+ # task_outputs: List[TaskOutput] = []
265
+
266
+ # for future_task, future, task_index in futures:
267
+ # task_output = future.result()
268
+ # task_outputs.append(task_output)
269
+ # future_task._store_execution_log(task_index, was_replayed)
270
+
271
+ # return task_outputs
272
+
273
+
274
+ # def _calculate_usage_metrics(self) -> UsageMetrics:
275
+ # """
276
+ # Calculate and return the usage metrics that consumed by the agent network.
277
+ # """
278
+ # total_usage_metrics = UsageMetrics()
279
+
280
+ # for member in self.members:
281
+ # agent = member.agent
282
+ # if hasattr(agent, "_token_process"):
283
+ # token_sum = agent._token_process.get_summary()
284
+ # total_usage_metrics.add_usage_metrics(token_sum)
285
+
286
+ # if self.managers:
287
+ # for manager in self.managers:
288
+ # if hasattr(manager.agent, "_token_process"):
289
+ # token_sum = manager.agent._token_process.get_summary()
290
+ # total_usage_metrics.add_usage_metrics(token_sum)
291
+
292
+ # self.usage_metrics = total_usage_metrics
293
+ # return total_usage_metrics
294
+
295
+
296
+ def _execute_tasks(self, tasks: List[Task], start_index: Optional[int] = None) -> Tuple[TaskOutput, TaskGraph]:
297
+ """Executes tasks and returns TaskOutput object as concl or latest response in the network."""
298
+ res, task_graph = None, None
299
+
300
+ if len(tasks) == 1:
301
+ task = self.tasks[0]
302
+ responsible_agent = self._get_responsible_agent(task=task)
303
+ res = task.execute(agent=responsible_agent)
304
+ return res, task_graph
305
+
306
+
307
+ nodes = [
308
+ Node(
309
+ task=task,
310
+ assigned_to=self._get_responsible_agent(task=task),
311
+ status=TaskStatus.NOT_STARTED if not start_index or i >= start_index else TaskStatus.COMPLETED,
312
+ ) for i, task in enumerate(tasks)
313
+ ]
314
+ task_graph = TaskGraph(nodes={node.identifier: node for node in nodes})
315
+
316
+ for i in range(0, len(nodes) - 1):
317
+ task_graph.add_edge(
318
+ source=nodes[i].identifier,
319
+ target=nodes[i+1].identifier,
320
+ edge=Edge(
321
+ weight=3 if nodes[i].task in self.manager_tasks else 1,
322
+ dependency_type=DependencyType.FINISH_TO_START if self.process == TaskHandlingProcess.HIERARCHY else DependencyType.START_TO_START,
323
+ required=bool(self.process == TaskHandlingProcess.CONSENSUAL),
324
+ condition=self.consent_trigger,
325
+ data_transfer=bool(self.process == TaskHandlingProcess.HIERARCHY),
326
+ )
327
+ )
302
328
 
303
- for member in self.members:
304
- agent = member.agent
305
- if hasattr(agent, "_token_process"):
306
- token_sum = agent._token_process.get_summary()
307
- total_usage_metrics.add_usage_metrics(token_sum)
329
+ if start_index is not None:
330
+ res, _ = task_graph.activate(target=nodes[start_index].indentifier)
308
331
 
309
- if self.managers:
310
- for manager in self.managers:
311
- if hasattr(manager.agent, "_token_process"):
312
- token_sum = manager.agent._token_process.get_summary()
313
- total_usage_metrics.add_usage_metrics(token_sum)
332
+ else:
333
+ res, _ = task_graph.activate()
314
334
 
315
- self.usage_metrics = total_usage_metrics
316
- return total_usage_metrics
335
+ # task_outputs: List[TaskOutput] = []
336
+ # lead_task_output: TaskOutput = None
337
+ # futures: List[Tuple[Task, Future[TaskOutput], int]] = []
338
+ # last_sync_output: Optional[TaskOutput] = None
317
339
 
340
+ # for task_index, task in enumerate(tasks):
341
+ # if start_index is not None and task_index < start_index:
342
+ # if task.output:
343
+ # if task.execution_type == TaskExecutionType.ASYNC:
344
+ # task_outputs.append(task.output)
345
+ # else:
346
+ # task_outputs = [task.output]
347
+ # last_sync_output = task.output
348
+ # continue
318
349
 
319
- def _execute_tasks(self, tasks: List[Task], start_index: Optional[int] = 0, was_replayed: bool = False) -> NetworkOutput:
320
- """
321
- Executes tasks sequentially and returns the final output in NetworkOutput class.
322
- When we have a manager agent, we will start from executing manager agent's tasks.
323
- Priority:
324
- 1. Network tasks > 2. Manager task > 3. Member tasks (in order of index)
325
- """
350
+ # responsible_agent = self._get_responsible_agent(task=task)
326
351
 
327
- task_outputs: List[TaskOutput] = []
328
- lead_task_output: TaskOutput = None
329
- futures: List[Tuple[Task, Future[TaskOutput], int]] = []
330
- last_sync_output: Optional[TaskOutput] = None
331
-
332
- for task_index, task in enumerate(tasks):
333
- if start_index is not None and task_index < start_index:
334
- if task.output:
335
- if task.execution_type == TaskExecutionType.ASYNC:
336
- task_outputs.append(task.output)
337
- else:
338
- task_outputs = [task.output]
339
- last_sync_output = task.output
340
- continue
341
-
342
- responsible_agent = self._get_responsible_agent(task)
343
- if responsible_agent is None:
344
- self._assign_tasks()
345
-
346
- ## commented out - this will be handled by node objects
347
- # if isinstance(task, ConditionalTask):
348
- # skipped_task_output = task._handle_conditional_task(task_outputs, futures, task_index, was_replayed)
349
- # if skipped_task_output:
350
- # continue
351
-
352
- # self._log_task_start(task, responsible_agent)
353
-
354
- if task.execution_type == TaskExecutionType.ASYNC:
355
- context = create_raw_outputs(tasks=[task, ], task_outputs=([last_sync_output,] if last_sync_output else []))
356
- future = task._execute_async(agent=responsible_agent, context=context)
357
- futures.append((task, future, task_index))
358
- else:
359
- context = create_raw_outputs(tasks=[task,], task_outputs=([last_sync_output,] if last_sync_output else [] ))
360
- task_output = task.execute(agent=responsible_agent, context=context)
352
+ # ## commented out - this will be handled by node objects
353
+ # # if isinstance(task, ConditionalTask):
354
+ # # skipped_task_output = task._handle_conditional_task(task_outputs, futures, task_index, was_replayed)
355
+ # # if skipped_task_output:
356
+ # # continue
357
+
358
+ # # self._log_task_start(task, responsible_agent)
361
359
 
362
- if self.managers and responsible_agent in [manager.agent for manager in self.managers]:
363
- lead_task_output = task_output
360
+ # context = create_raw_outputs(tasks=[task, ], task_outputs=([last_sync_output,] if last_sync_output else []))
361
+ # res = task.execute(agent=responsible_agent, context=context)
364
362
 
365
- task_outputs.append(task_output)
366
- task._store_execution_log(task_index, was_replayed, self._inputs)
363
+ # if isinstance(res, Future):
364
+ # futures.append((task, res, task_index))
365
+ # else:
366
+ # # if self.managers and responsible_agent in [manager.agent for manager in self.managers]:
367
+ # # lead_task_output = task_output
367
368
 
369
+ # task_outputs.append(res)
370
+ # task._store_log(task_index, was_replayed, self._inputs)
368
371
 
369
- if futures:
370
- task_outputs = self._process_async_tasks(futures, was_replayed)
371
372
 
372
- if not task_outputs:
373
+ # if futures:
374
+ # task_outputs = self._process_async_tasks(futures, was_replayed)
375
+
376
+ if not res:
373
377
  Logger().log(level="error", message="Missing task outputs.", color="red")
374
378
  raise ValueError("Missing task outputs")
375
379
 
376
- final_task_output = lead_task_output if lead_task_output is not None else task_outputs[0] #! REFINEME
377
-
378
- # token_usage = self._calculate_usage_metrics() #! combining with Eval
380
+ return res, task_graph
379
381
 
380
- return NetworkOutput(
381
- network_id=self.id,
382
- raw=final_task_output.raw,
383
- json_dict=final_task_output.json_dict,
384
- pydantic=final_task_output.pydantic,
385
- task_outputs=task_outputs,
386
- # token_usage=token_usage,
387
- )
388
382
 
389
383
 
390
- def launch(self, kwargs_pre: Optional[Dict[str, str]] = None, kwargs_post: Optional[Dict[str, Any]] = None) -> NetworkOutput:
384
+ def launch(
385
+ self, kwargs_pre: Optional[Dict[str, str]] = None, kwargs_post: Optional[Dict[str, Any]] = None, start_index: int = None
386
+ ) -> Tuple[TaskOutput, TaskGraph]:
391
387
  """
392
388
  Launch the agent network - executing tasks and recording their outputs.
393
389
  """
394
390
 
395
- metrics: List[UsageMetrics] = []
391
+ self._assign_tasks()
396
392
 
397
- if self.network_tasks or self.member_tasks_without_agent:
398
- self._assign_tasks()
399
-
400
- if kwargs_pre is not None:
393
+ if kwargs_pre:
401
394
  for func in self.pre_launch_callbacks: # signature check
402
395
  func(**kwargs_pre)
403
396
 
404
397
  for member in self.members:
405
398
  agent = member.agent
406
- agent.networks.append(self)
399
+
400
+ if not agent.networks:
401
+ agent.networks.append(self)
407
402
 
408
403
  if self.step_callback:
409
404
  agent.callbacks.append(self.step_callback)
410
405
 
411
406
  if self.process is None:
412
- self.process = TaskHandlingProcess.SEQUENT
407
+ self.process = TaskHandlingProcess.SEQUENTIAL
413
408
 
414
- result = self._execute_tasks(self.tasks)
409
+ result, tg = self._execute_tasks(self.tasks, start_index=start_index)
410
+ callback_output = None
415
411
 
416
412
  for func in self.post_launch_callbacks:
417
- result = func(result, **kwargs_post)
413
+ callback_output = func(result, **kwargs_post)
414
+
415
+ if callback_output:
416
+ match result:
417
+ case TaskOutput():
418
+ result.callback_output = callback_output
419
+
420
+ case _:
421
+ pass
418
422
 
419
- metrics += [member.agent._token_process.get_summary() for member in self.members]
423
+ # metrics += [member.agent._token_process.get_summary() for member in self.members]
420
424
 
421
- self.usage_metrics = UsageMetrics()
422
- for metric in metrics:
423
- self.usage_metrics.add_usage_metrics(metric)
425
+ # self.usage_metrics = UsageMetrics()
426
+ # for metric in metrics:
427
+ # self.usage_metrics.add_usage_metrics(metric)
424
428
 
425
- return result
429
+ return result, tg
426
430
 
427
431
 
428
432
  @property
@@ -474,7 +478,7 @@ class AgentNetwork(BaseModel):
474
478
 
475
479
 
476
480
  @property
477
- def member_tasks_without_agent(self) -> List[Task]:
481
+ def unassigned_member_tasks(self) -> List[Task]:
478
482
  res = list()
479
483
 
480
484
  if self.members:
versionhq/llm/model.py CHANGED
@@ -237,6 +237,41 @@ class LLM(BaseModel):
237
237
  return valid_params
238
238
 
239
239
 
240
+ def _supports_function_calling(self) -> bool:
241
+ try:
242
+ if self.model:
243
+ params = litellm.get_supported_openai_params(model=self.model)
244
+ return "response_format" in params if params else False
245
+ except Exception as e:
246
+ self._logger.log(level="warning", message=f"Failed to get supported params: {str(e)}", color="yellow")
247
+ return False
248
+
249
+
250
+ def _supports_stop_words(self) -> bool:
251
+ supported_params = litellm.get_supported_openai_params(model=self.model, custom_llm_provider=self.endpoint_provider)
252
+ return "stop" in supported_params if supported_params else False
253
+
254
+
255
+ def _get_context_window_size(self) -> int:
256
+ """
257
+ Only use 75% of the context window size to avoid cutting the message in the middle.
258
+ """
259
+ return int(LLM_CONTEXT_WINDOW_SIZES.get(self.model) * 0.75) if LLM_CONTEXT_WINDOW_SIZES.get(self.model) is not None else DEFAULT_CONTEXT_WINDOW_SIZE
260
+
261
+
262
+ def _set_callbacks(self, callbacks: List[Any]):
263
+ callback_types = [type(callback) for callback in callbacks]
264
+ for callback in litellm.success_callback[:]:
265
+ if type(callback) in callback_types:
266
+ litellm.success_callback.remove(callback)
267
+
268
+ for callback in litellm._async_success_callback[:]:
269
+ if type(callback) in callback_types:
270
+ litellm._async_success_callback.remove(callback)
271
+
272
+ litellm.callbacks = callbacks
273
+
274
+
240
275
  def call(
241
276
  self,
242
277
  messages: List[Dict[str, str]],
@@ -345,38 +380,3 @@ class LLM(BaseModel):
345
380
  self._logger.log(level="error", message=f"{self.model} failed to execute: {str(e)}", color="red")
346
381
  if "litellm.RateLimitError" in str(e):
347
382
  raise e
348
-
349
-
350
- def _supports_function_calling(self) -> bool:
351
- try:
352
- if self.model:
353
- params = litellm.get_supported_openai_params(model=self.model)
354
- return "response_format" in params if params else False
355
- except Exception as e:
356
- self._logger.log(level="warning", message=f"Failed to get supported params: {str(e)}", color="yellow")
357
- return False
358
-
359
-
360
- def _supports_stop_words(self) -> bool:
361
- supported_params = litellm.get_supported_openai_params(model=self.model, custom_llm_provider=self.endpoint_provider)
362
- return "stop" in supported_params if supported_params else False
363
-
364
-
365
- def _get_context_window_size(self) -> int:
366
- """
367
- Only use 75% of the context window size to avoid cutting the message in the middle.
368
- """
369
- return int(LLM_CONTEXT_WINDOW_SIZES.get(self.model) * 0.75) if LLM_CONTEXT_WINDOW_SIZES.get(self.model) is not None else DEFAULT_CONTEXT_WINDOW_SIZE
370
-
371
-
372
- def _set_callbacks(self, callbacks: List[Any]):
373
- callback_types = [type(callback) for callback in callbacks]
374
- for callback in litellm.success_callback[:]:
375
- if type(callback) in callback_types:
376
- litellm.success_callback.remove(callback)
377
-
378
- for callback in litellm._async_success_callback[:]:
379
- if type(callback) in callback_types:
380
- litellm._async_success_callback.remove(callback)
381
-
382
- litellm.callbacks = callbacks
versionhq/memory/model.py CHANGED
@@ -34,12 +34,14 @@ class MemoryMetadata:
34
34
 
35
35
  def __init__(
36
36
  self,
37
+ task_description: str = None,
37
38
  eval_criteria: Optional[str] = None,
38
39
  score: Optional[int | float] = None,
39
40
  suggestion: Optional[str] = None,
40
41
  eval_by: Optional[str] = None, # task evaluator agent
41
42
  config: Optional[Dict[str, Any]] = None
42
43
  ):
44
+ self.task_description = task_description
43
45
  self.eval_criteria = eval_criteria
44
46
  self.score = score
45
47
  self.suggestion = suggestion
@@ -104,7 +106,7 @@ class MemoryItem:
104
106
 
105
107
  class ShortTermMemory(Memory):
106
108
  """
107
- A class for managing transient data related to immediate tasks and interactions.
109
+ A Pydantic class to store agents' short-term memories.
108
110
  - Type: stm
109
111
  - Storage: Mem0Storage | RAGStorage
110
112
  """
@@ -165,7 +167,7 @@ class ShortTermMemory(Memory):
165
167
 
166
168
  class LongTermMemory(Memory):
167
169
  """
168
- A class for managing cross runs data related to overall task executions.
170
+ A Pydantic class for storing agents' long-term memories. Query task outputs for the evaluation.
169
171
  - Type: ltm
170
172
  - Storage: LTMSQLiteStorage | RAGStorage
171
173
  """