camel-ai 0.2.76a14__py3-none-any.whl → 0.2.78__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.
Potentially problematic release.
This version of camel-ai might be problematic. Click here for more details.
- camel/__init__.py +1 -1
- camel/agents/chat_agent.py +278 -154
- camel/data_collectors/alpaca_collector.py +15 -6
- camel/societies/workforce/prompts.py +131 -50
- camel/societies/workforce/single_agent_worker.py +390 -11
- camel/societies/workforce/structured_output_handler.py +30 -18
- camel/societies/workforce/utils.py +105 -12
- camel/societies/workforce/workforce.py +818 -224
- camel/societies/workforce/workforce_logger.py +24 -5
- camel/toolkits/context_summarizer_toolkit.py +2 -2
- camel/toolkits/excel_toolkit.py +1 -1
- camel/toolkits/file_toolkit.py +3 -2
- camel/toolkits/terminal_toolkit/utils.py +106 -154
- camel/types/enums.py +4 -4
- camel/utils/context_utils.py +379 -22
- {camel_ai-0.2.76a14.dist-info → camel_ai-0.2.78.dist-info}/METADATA +10 -1
- {camel_ai-0.2.76a14.dist-info → camel_ai-0.2.78.dist-info}/RECORD +19 -19
- {camel_ai-0.2.76a14.dist-info → camel_ai-0.2.78.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.76a14.dist-info → camel_ai-0.2.78.dist-info}/licenses/LICENSE +0 -0
|
@@ -42,6 +42,36 @@ class TaskResult(BaseModel):
|
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
class QualityEvaluation(BaseModel):
|
|
46
|
+
r"""Quality evaluation result for a completed task.
|
|
47
|
+
|
|
48
|
+
.. deprecated::
|
|
49
|
+
Use :class:`TaskAnalysisResult` instead. This class is kept for
|
|
50
|
+
backward compatibility.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
quality_sufficient: bool = Field(
|
|
54
|
+
description="Whether the task result meets quality standards."
|
|
55
|
+
)
|
|
56
|
+
quality_score: int = Field(
|
|
57
|
+
description="Quality score from 0 to 100.", ge=0, le=100
|
|
58
|
+
)
|
|
59
|
+
issues: List[str] = Field(
|
|
60
|
+
default_factory=list,
|
|
61
|
+
description="List of quality issues found in the result.",
|
|
62
|
+
)
|
|
63
|
+
recovery_strategy: Optional[str] = Field(
|
|
64
|
+
default=None,
|
|
65
|
+
description="Recommended recovery strategy if quality is "
|
|
66
|
+
"insufficient: "
|
|
67
|
+
"'retry', 'reassign', 'replan', or 'decompose'.",
|
|
68
|
+
)
|
|
69
|
+
modified_task_content: Optional[str] = Field(
|
|
70
|
+
default=None,
|
|
71
|
+
description="Modified task content for replan strategy.",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
45
75
|
class TaskAssignment(BaseModel):
|
|
46
76
|
r"""An individual task assignment within a batch."""
|
|
47
77
|
|
|
@@ -52,7 +82,8 @@ class TaskAssignment(BaseModel):
|
|
|
52
82
|
dependencies: List[str] = Field(
|
|
53
83
|
default_factory=list,
|
|
54
84
|
description="List of task IDs that must complete before this task. "
|
|
55
|
-
"This is critical for the task decomposition and
|
|
85
|
+
"This is critical for the task decomposition and "
|
|
86
|
+
"execution.",
|
|
56
87
|
)
|
|
57
88
|
|
|
58
89
|
# Allow LLMs to output dependencies as a comma-separated string or empty
|
|
@@ -60,7 +91,8 @@ class TaskAssignment(BaseModel):
|
|
|
60
91
|
# downstream logic does not break with validation errors.
|
|
61
92
|
@staticmethod
|
|
62
93
|
def _split_and_strip(dep_str: str) -> List[str]:
|
|
63
|
-
r"""Utility to split a comma separated string and strip
|
|
94
|
+
r"""Utility to split a comma separated string and strip
|
|
95
|
+
whitespace."""
|
|
64
96
|
return [d.strip() for d in dep_str.split(',') if d.strip()]
|
|
65
97
|
|
|
66
98
|
@field_validator("dependencies", mode="before")
|
|
@@ -74,7 +106,8 @@ class TaskAssignment(BaseModel):
|
|
|
74
106
|
|
|
75
107
|
|
|
76
108
|
class TaskAssignResult(BaseModel):
|
|
77
|
-
r"""The result of task assignment for both single and batch
|
|
109
|
+
r"""The result of task assignment for both single and batch
|
|
110
|
+
assignments."""
|
|
78
111
|
|
|
79
112
|
assignments: List[TaskAssignment] = Field(
|
|
80
113
|
description="List of task assignments."
|
|
@@ -88,6 +121,7 @@ class RecoveryStrategy(str, Enum):
|
|
|
88
121
|
REPLAN = "replan"
|
|
89
122
|
DECOMPOSE = "decompose"
|
|
90
123
|
CREATE_WORKER = "create_worker"
|
|
124
|
+
REASSIGN = "reassign"
|
|
91
125
|
|
|
92
126
|
def __str__(self):
|
|
93
127
|
return self.value
|
|
@@ -116,17 +150,75 @@ class FailureContext(BaseModel):
|
|
|
116
150
|
)
|
|
117
151
|
|
|
118
152
|
|
|
119
|
-
class
|
|
120
|
-
r"""
|
|
153
|
+
class TaskAnalysisResult(BaseModel):
|
|
154
|
+
r"""Unified result for task failure analysis and quality evaluation.
|
|
155
|
+
|
|
156
|
+
This model combines both failure recovery decisions and quality evaluation
|
|
157
|
+
results into a single structure. For failure analysis, only the recovery
|
|
158
|
+
strategy and reasoning fields are populated. For quality evaluation, all
|
|
159
|
+
fields including quality_score and issues are populated.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
# Common fields - always populated
|
|
163
|
+
reasoning: str = Field(
|
|
164
|
+
description="Explanation for the analysis result or recovery "
|
|
165
|
+
"decision"
|
|
166
|
+
)
|
|
121
167
|
|
|
122
|
-
|
|
123
|
-
|
|
168
|
+
recovery_strategy: Optional[RecoveryStrategy] = Field(
|
|
169
|
+
default=None,
|
|
170
|
+
description="Recommended recovery strategy: 'retry', 'replan', "
|
|
171
|
+
"'decompose', 'create_worker', or 'reassign'. None indicates no "
|
|
172
|
+
"recovery needed (quality sufficient).",
|
|
124
173
|
)
|
|
125
|
-
|
|
174
|
+
|
|
126
175
|
modified_task_content: Optional[str] = Field(
|
|
127
|
-
default=None,
|
|
176
|
+
default=None,
|
|
177
|
+
description="Modified task content if strategy requires replan",
|
|
128
178
|
)
|
|
129
179
|
|
|
180
|
+
# Quality-specific fields - populated only for quality evaluation
|
|
181
|
+
quality_score: Optional[int] = Field(
|
|
182
|
+
default=None,
|
|
183
|
+
description="Quality score from 0 to 100 (only for quality "
|
|
184
|
+
"evaluation). "
|
|
185
|
+
"None indicates this is a failure analysis, "
|
|
186
|
+
"not quality evaluation.",
|
|
187
|
+
ge=0,
|
|
188
|
+
le=100,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
issues: List[str] = Field(
|
|
192
|
+
default_factory=list,
|
|
193
|
+
description="List of issues found. For failures: error details. "
|
|
194
|
+
"For quality evaluation: quality issues.",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def is_quality_evaluation(self) -> bool:
|
|
199
|
+
r"""Check if this is a quality evaluation result.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
bool: True if this is a quality evaluation (has quality_score),
|
|
203
|
+
False if this is a failure analysis.
|
|
204
|
+
"""
|
|
205
|
+
return self.quality_score is not None
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def quality_sufficient(self) -> bool:
|
|
209
|
+
r"""For quality evaluations, check if quality meets standards.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
bool: True if quality is sufficient (score >= 70 and no recovery
|
|
213
|
+
strategy recommended), False otherwise. Always False for
|
|
214
|
+
failure analysis results.
|
|
215
|
+
"""
|
|
216
|
+
return (
|
|
217
|
+
self.quality_score is not None
|
|
218
|
+
and self.quality_score >= 70
|
|
219
|
+
and self.recovery_strategy is None
|
|
220
|
+
)
|
|
221
|
+
|
|
130
222
|
|
|
131
223
|
def check_if_running(
|
|
132
224
|
running: bool,
|
|
@@ -178,7 +270,7 @@ def check_if_running(
|
|
|
178
270
|
if retries < max_retries:
|
|
179
271
|
logger.warning(
|
|
180
272
|
f"{error_msg} Retrying in {retry_delay}s... "
|
|
181
|
-
f"(Attempt {retries+1}/{max_retries})"
|
|
273
|
+
f"(Attempt {retries + 1}/{max_retries})"
|
|
182
274
|
)
|
|
183
275
|
time.sleep(retry_delay)
|
|
184
276
|
retries += 1
|
|
@@ -200,7 +292,7 @@ def check_if_running(
|
|
|
200
292
|
logger.warning(
|
|
201
293
|
f"Exception in {func.__name__}: {e}. "
|
|
202
294
|
f"Retrying in {retry_delay}s... "
|
|
203
|
-
f"(Attempt {retries+1}/{max_retries})"
|
|
295
|
+
f"(Attempt {retries + 1}/{max_retries})"
|
|
204
296
|
)
|
|
205
297
|
time.sleep(retry_delay)
|
|
206
298
|
retries += 1
|
|
@@ -218,7 +310,8 @@ def check_if_running(
|
|
|
218
310
|
# This should not be reached, but just in case
|
|
219
311
|
if handle_exceptions:
|
|
220
312
|
logger.error(
|
|
221
|
-
f"Unexpected failure in {func.__name__}:
|
|
313
|
+
f"Unexpected failure in {func.__name__}: "
|
|
314
|
+
f"{last_exception}"
|
|
222
315
|
)
|
|
223
316
|
return None
|
|
224
317
|
else:
|