camel-ai 0.2.76a14__py3-none-any.whl → 0.2.77__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 +591 -171
- 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/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.77.dist-info}/METADATA +1 -1
- {camel_ai-0.2.76a14.dist-info → camel_ai-0.2.77.dist-info}/RECORD +17 -17
- {camel_ai-0.2.76a14.dist-info → camel_ai-0.2.77.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.76a14.dist-info → camel_ai-0.2.77.dist-info}/licenses/LICENSE +0 -0
camel/utils/context_utils.py
CHANGED
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
import os
|
|
16
16
|
from datetime import datetime
|
|
17
17
|
from pathlib import Path
|
|
18
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
18
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, Field
|
|
19
21
|
|
|
20
22
|
from camel.logger import get_logger
|
|
21
23
|
|
|
@@ -26,6 +28,93 @@ if TYPE_CHECKING:
|
|
|
26
28
|
logger = get_logger(__name__)
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
class WorkflowSummary(BaseModel):
|
|
32
|
+
r"""Pydantic model for structured workflow summaries.
|
|
33
|
+
|
|
34
|
+
This model defines the schema for workflow memories that can be reused
|
|
35
|
+
by future agents for similar tasks.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
task_title: str = Field(
|
|
39
|
+
description="A short, generic title of the main task (≤ 10 words). "
|
|
40
|
+
"Avoid product- or case-specific names. "
|
|
41
|
+
"Example: 'List GitHub stargazers', "
|
|
42
|
+
"'Remind weekly meetings on Slack', "
|
|
43
|
+
"'Find best leads and turn them into a table on Notion'."
|
|
44
|
+
)
|
|
45
|
+
task_description: str = Field(
|
|
46
|
+
description="One-paragraph summary of what the user asked for "
|
|
47
|
+
"(≤ 80 words). "
|
|
48
|
+
"No implementation details; just the outcome the user wants. "
|
|
49
|
+
"Example: Find academic professors who might be interested in the "
|
|
50
|
+
"upcoming research paper on Graph-based Agentic Memory, extract "
|
|
51
|
+
"their email addresses, affiliations, and research interests, "
|
|
52
|
+
"and create a table on Notion with this information."
|
|
53
|
+
)
|
|
54
|
+
tools: List[str] = Field(
|
|
55
|
+
description="Bullet list of tool calls or functions calls used. "
|
|
56
|
+
"For each: name → what it did → why it was useful (one line each). "
|
|
57
|
+
"This field is explicitly for tool call messages or the MCP "
|
|
58
|
+
"servers used."
|
|
59
|
+
"Example: - ArxivToolkit: get authors from a paper title, "
|
|
60
|
+
"it helped find academic professors who authored a particular "
|
|
61
|
+
"paper, and then get their email addresses, affiliations, and "
|
|
62
|
+
"research interests.",
|
|
63
|
+
default_factory=list,
|
|
64
|
+
)
|
|
65
|
+
steps: List[str] = Field(
|
|
66
|
+
description="Numbered, ordered actions the agent took to complete "
|
|
67
|
+
"the task. Each step starts with a verb and is generic "
|
|
68
|
+
"enough to be repeatable. "
|
|
69
|
+
"Example: 1. Find the upcoming meetings on Google Calendar "
|
|
70
|
+
" today. 2. Send participants a reminder on Slack...",
|
|
71
|
+
default_factory=list,
|
|
72
|
+
)
|
|
73
|
+
failure_and_recovery_strategies: List[str] = Field(
|
|
74
|
+
description="[Optional] Bullet each incident with symptom, "
|
|
75
|
+
" cause (if known), fix/workaround, verification of "
|
|
76
|
+
"recovery. Leave empty if no failures. "
|
|
77
|
+
"failures. Example: Running the script for consumer data "
|
|
78
|
+
"analysis failed since Pandas package was not installed. "
|
|
79
|
+
"Fixed by running 'pip install pandas'.",
|
|
80
|
+
default_factory=list,
|
|
81
|
+
)
|
|
82
|
+
notes_and_observations: str = Field(
|
|
83
|
+
description="[Optional] Anything not covered in previous fields "
|
|
84
|
+
"that is critical to know for future executions of the task. "
|
|
85
|
+
"Leave empty if no notes. Do not repeat any information, or "
|
|
86
|
+
"mention trivial details. Only what is essential. "
|
|
87
|
+
"Example: The user likes to be in the "
|
|
88
|
+
"loop of the task execution, make sure to check with them the "
|
|
89
|
+
"plan before starting to work, and ask them for approval "
|
|
90
|
+
"mid-task by using the HumanToolkit.",
|
|
91
|
+
default="",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def get_instruction_prompt(cls) -> str:
|
|
96
|
+
r"""Get the instruction prompt for this model.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
str: The instruction prompt that guides agents to produce
|
|
100
|
+
structured output matching this schema.
|
|
101
|
+
"""
|
|
102
|
+
return (
|
|
103
|
+
'You are writing a compact "workflow memory" so future agents '
|
|
104
|
+
'can reuse what you just did for future tasks. '
|
|
105
|
+
'Be concise, precise, and action-oriented. Analyze the '
|
|
106
|
+
'conversation and extract the key workflow information '
|
|
107
|
+
'following the provided schema structure. If a field has no '
|
|
108
|
+
'content, still include it per the schema, but keep it empty. '
|
|
109
|
+
'The length of your workflow must be proportional to the '
|
|
110
|
+
'complexity of the task. Example: If the task is simply '
|
|
111
|
+
'about a simple math problem, the workflow must be short, '
|
|
112
|
+
'e.g. <60 words. By contrast, if the task is complex and '
|
|
113
|
+
'multi-step, such as finding particular job applications based '
|
|
114
|
+
'on user CV, the workflow must be longer, e.g. about 120 words.'
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
29
118
|
class ContextUtility:
|
|
30
119
|
r"""Utility class for context management and file operations.
|
|
31
120
|
|
|
@@ -39,23 +128,46 @@ class ContextUtility:
|
|
|
39
128
|
- Text-based search through files
|
|
40
129
|
- File metadata handling
|
|
41
130
|
- Agent memory record retrieval
|
|
131
|
+
- Shared session management for workforce workflows
|
|
42
132
|
"""
|
|
43
133
|
|
|
44
|
-
|
|
134
|
+
# Class variables for shared session management
|
|
135
|
+
_shared_sessions: ClassVar[Dict[str, 'ContextUtility']] = {}
|
|
136
|
+
_default_workforce_session: ClassVar[Optional['ContextUtility']] = None
|
|
137
|
+
|
|
138
|
+
def __init__(
|
|
139
|
+
self,
|
|
140
|
+
working_directory: Optional[str] = None,
|
|
141
|
+
session_id: Optional[str] = None,
|
|
142
|
+
create_folder: bool = True,
|
|
143
|
+
):
|
|
45
144
|
r"""Initialize the ContextUtility.
|
|
46
145
|
|
|
47
146
|
Args:
|
|
48
147
|
working_directory (str, optional): The directory path where files
|
|
49
148
|
will be stored. If not provided, a default directory will be
|
|
50
149
|
used.
|
|
150
|
+
session_id (str, optional): The session ID to use. If provided,
|
|
151
|
+
this instance will use the same session folder as other
|
|
152
|
+
instances with the same session_id. If not provided, a new
|
|
153
|
+
session ID will be generated.
|
|
154
|
+
create_folder (bool): Whether to create the session folder
|
|
155
|
+
immediately. If False, the folder will be created only when
|
|
156
|
+
needed (e.g., when saving files). Default is True for
|
|
157
|
+
backward compatibility.
|
|
51
158
|
"""
|
|
52
159
|
self.working_directory_param = working_directory
|
|
53
|
-
self._setup_storage(working_directory)
|
|
160
|
+
self._setup_storage(working_directory, session_id, create_folder)
|
|
54
161
|
|
|
55
|
-
def _setup_storage(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
162
|
+
def _setup_storage(
|
|
163
|
+
self,
|
|
164
|
+
working_directory: Optional[str],
|
|
165
|
+
session_id: Optional[str] = None,
|
|
166
|
+
create_folder: bool = True,
|
|
167
|
+
) -> None:
|
|
168
|
+
r"""Initialize session-specific storage paths and optionally create
|
|
169
|
+
directory structure for context file management."""
|
|
170
|
+
self.session_id = session_id or self._generate_session_id()
|
|
59
171
|
|
|
60
172
|
if working_directory:
|
|
61
173
|
self.working_directory = Path(working_directory).resolve()
|
|
@@ -68,7 +180,10 @@ class ContextUtility:
|
|
|
68
180
|
|
|
69
181
|
# Create session-specific directory
|
|
70
182
|
self.working_directory = self.working_directory / self.session_id
|
|
71
|
-
|
|
183
|
+
|
|
184
|
+
# Only create directory if requested
|
|
185
|
+
if create_folder:
|
|
186
|
+
self.working_directory.mkdir(parents=True, exist_ok=True)
|
|
72
187
|
|
|
73
188
|
def _generate_session_id(self) -> str:
|
|
74
189
|
r"""Create timestamp-based unique identifier for isolating
|
|
@@ -78,6 +193,10 @@ class ContextUtility:
|
|
|
78
193
|
|
|
79
194
|
# ========= GENERIC FILE MANAGEMENT METHODS =========
|
|
80
195
|
|
|
196
|
+
def _ensure_directory_exists(self) -> None:
|
|
197
|
+
r"""Ensure the working directory exists, creating it if necessary."""
|
|
198
|
+
self.working_directory.mkdir(parents=True, exist_ok=True)
|
|
199
|
+
|
|
81
200
|
def _create_or_update_note(self, note_name: str, content: str) -> str:
|
|
82
201
|
r"""Write content to markdown file, creating new file or
|
|
83
202
|
overwriting existing one with UTF-8 encoding.
|
|
@@ -90,6 +209,8 @@ class ContextUtility:
|
|
|
90
209
|
str: Success message.
|
|
91
210
|
"""
|
|
92
211
|
try:
|
|
212
|
+
# Ensure directory exists before writing
|
|
213
|
+
self._ensure_directory_exists()
|
|
93
214
|
file_path = self.working_directory / f"{note_name}.md"
|
|
94
215
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
95
216
|
f.write(content)
|
|
@@ -114,7 +235,8 @@ class ContextUtility:
|
|
|
114
235
|
metadata (Dict, optional): Additional metadata to include.
|
|
115
236
|
|
|
116
237
|
Returns:
|
|
117
|
-
str:
|
|
238
|
+
str: "success" on success, error message starting with "Error:"
|
|
239
|
+
on failure.
|
|
118
240
|
"""
|
|
119
241
|
try:
|
|
120
242
|
markdown_content = ""
|
|
@@ -135,14 +257,99 @@ class ContextUtility:
|
|
|
135
257
|
|
|
136
258
|
self._create_or_update_note(filename, markdown_content)
|
|
137
259
|
logger.info(
|
|
138
|
-
f"Markdown file saved to "
|
|
260
|
+
f"Markdown file '{filename}.md' saved successfully to "
|
|
139
261
|
f"{self.working_directory / f'{filename}.md'}"
|
|
140
262
|
)
|
|
141
|
-
return
|
|
263
|
+
return "success"
|
|
142
264
|
|
|
143
265
|
except Exception as e:
|
|
144
266
|
logger.error(f"Error saving markdown file {filename}: {e}")
|
|
145
|
-
return f"Error
|
|
267
|
+
return f"Error: {e}"
|
|
268
|
+
|
|
269
|
+
def structured_output_to_markdown(
|
|
270
|
+
self,
|
|
271
|
+
structured_data: BaseModel,
|
|
272
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
273
|
+
title: Optional[str] = None,
|
|
274
|
+
field_mappings: Optional[Dict[str, str]] = None,
|
|
275
|
+
) -> str:
|
|
276
|
+
r"""Convert any Pydantic BaseModel instance to markdown format.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
structured_data: Any Pydantic BaseModel instance
|
|
280
|
+
metadata: Optional metadata to include in the markdown
|
|
281
|
+
title: Optional custom title, defaults to model class name
|
|
282
|
+
field_mappings: Optional mapping of field names to custom
|
|
283
|
+
section titles
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
str: Markdown formatted content
|
|
287
|
+
"""
|
|
288
|
+
markdown_content = []
|
|
289
|
+
|
|
290
|
+
# Add metadata if provided
|
|
291
|
+
if metadata:
|
|
292
|
+
markdown_content.append("## Metadata\n")
|
|
293
|
+
for key, value in metadata.items():
|
|
294
|
+
markdown_content.append(f"- {key}: {value}")
|
|
295
|
+
markdown_content.append("")
|
|
296
|
+
|
|
297
|
+
# Add title
|
|
298
|
+
if title:
|
|
299
|
+
markdown_content.extend([f"## {title}", ""])
|
|
300
|
+
else:
|
|
301
|
+
model_name = structured_data.__class__.__name__
|
|
302
|
+
markdown_content.extend([f"## {model_name}", ""])
|
|
303
|
+
|
|
304
|
+
# Get model fields and values
|
|
305
|
+
model_dict = structured_data.model_dump()
|
|
306
|
+
|
|
307
|
+
for field_name, field_value in model_dict.items():
|
|
308
|
+
# Use custom mapping or convert field name to title case
|
|
309
|
+
if field_mappings and field_name in field_mappings:
|
|
310
|
+
section_title = field_mappings[field_name]
|
|
311
|
+
else:
|
|
312
|
+
# Convert snake_case to Title Case
|
|
313
|
+
section_title = field_name.replace('_', ' ').title()
|
|
314
|
+
|
|
315
|
+
markdown_content.append(f"### {section_title}")
|
|
316
|
+
|
|
317
|
+
# Handle different data types
|
|
318
|
+
if isinstance(field_value, list):
|
|
319
|
+
if field_value:
|
|
320
|
+
for i, item in enumerate(field_value):
|
|
321
|
+
if isinstance(item, str):
|
|
322
|
+
# Check if it looks like a numbered item already
|
|
323
|
+
if item.strip() and not item.strip()[0].isdigit():
|
|
324
|
+
# For steps or numbered lists, add numbers
|
|
325
|
+
if 'step' in field_name.lower():
|
|
326
|
+
markdown_content.append(f"{i + 1}. {item}")
|
|
327
|
+
else:
|
|
328
|
+
markdown_content.append(f"- {item}")
|
|
329
|
+
else:
|
|
330
|
+
markdown_content.append(f"- {item}")
|
|
331
|
+
else:
|
|
332
|
+
markdown_content.append(f"- {item!s}")
|
|
333
|
+
else:
|
|
334
|
+
markdown_content.append(
|
|
335
|
+
f"(No {section_title.lower()} recorded)"
|
|
336
|
+
)
|
|
337
|
+
elif isinstance(field_value, str):
|
|
338
|
+
if field_value.strip():
|
|
339
|
+
markdown_content.append(field_value)
|
|
340
|
+
else:
|
|
341
|
+
markdown_content.append(
|
|
342
|
+
f"(No {section_title.lower()} provided)"
|
|
343
|
+
)
|
|
344
|
+
elif isinstance(field_value, dict):
|
|
345
|
+
for k, v in field_value.items():
|
|
346
|
+
markdown_content.append(f"- **{k}**: {v}")
|
|
347
|
+
else:
|
|
348
|
+
markdown_content.append(str(field_value))
|
|
349
|
+
|
|
350
|
+
markdown_content.append("")
|
|
351
|
+
|
|
352
|
+
return "\n".join(markdown_content)
|
|
146
353
|
|
|
147
354
|
def load_markdown_file(self, filename: str) -> str:
|
|
148
355
|
r"""Generic method to load any markdown file.
|
|
@@ -394,15 +601,40 @@ class ContextUtility:
|
|
|
394
601
|
"""
|
|
395
602
|
return self.session_id
|
|
396
603
|
|
|
604
|
+
def set_session_id(self, session_id: str) -> None:
|
|
605
|
+
r"""Set a new session ID and update the working directory accordingly.
|
|
606
|
+
|
|
607
|
+
This allows sharing session directories between multiple ContextUtility
|
|
608
|
+
instances by using the same session_id.
|
|
609
|
+
|
|
610
|
+
Args:
|
|
611
|
+
session_id (str): The session ID to use.
|
|
612
|
+
"""
|
|
613
|
+
self.session_id = session_id
|
|
614
|
+
|
|
615
|
+
# Update working directory with new session_id
|
|
616
|
+
if self.working_directory_param:
|
|
617
|
+
base_dir = Path(self.working_directory_param).resolve()
|
|
618
|
+
else:
|
|
619
|
+
camel_workdir = os.environ.get("CAMEL_WORKDIR")
|
|
620
|
+
if camel_workdir:
|
|
621
|
+
base_dir = Path(camel_workdir) / "context_files"
|
|
622
|
+
else:
|
|
623
|
+
base_dir = Path("context_files")
|
|
624
|
+
|
|
625
|
+
self.working_directory = base_dir / self.session_id
|
|
626
|
+
self.working_directory.mkdir(parents=True, exist_ok=True)
|
|
627
|
+
|
|
397
628
|
def load_markdown_context_to_memory(
|
|
398
|
-
self, agent: "ChatAgent", filename: str
|
|
629
|
+
self, agent: "ChatAgent", filename: str, include_metadata: bool = False
|
|
399
630
|
) -> str:
|
|
400
631
|
r"""Load context from a markdown file and append it to agent memory.
|
|
401
|
-
Preserves existing conversation history without wiping it.
|
|
402
632
|
|
|
403
633
|
Args:
|
|
404
634
|
agent (ChatAgent): The agent to append context to.
|
|
405
635
|
filename (str): Name of the markdown file (without .md extension).
|
|
636
|
+
include_metadata (bool): Whether to include metadata section in the
|
|
637
|
+
loaded content. Defaults to False.
|
|
406
638
|
|
|
407
639
|
Returns:
|
|
408
640
|
str: Status message indicating success or failure with details.
|
|
@@ -413,24 +645,52 @@ class ContextUtility:
|
|
|
413
645
|
if not content.strip():
|
|
414
646
|
return f"Context file not found or empty: {filename}"
|
|
415
647
|
|
|
416
|
-
|
|
648
|
+
# Filter out metadata section if not requested
|
|
649
|
+
if not include_metadata:
|
|
650
|
+
content = self._filter_metadata_from_content(content)
|
|
651
|
+
|
|
417
652
|
from camel.types import OpenAIBackendRole
|
|
418
653
|
|
|
419
654
|
prefix_prompt = (
|
|
420
655
|
"The following is the context from a previous "
|
|
421
|
-
"session or workflow
|
|
656
|
+
"session or workflow which might be useful for "
|
|
657
|
+
"to the current task. This information might help you "
|
|
422
658
|
"understand the background, choose which tools to use, "
|
|
423
659
|
"and plan your next steps."
|
|
424
660
|
)
|
|
425
661
|
|
|
426
|
-
#
|
|
427
|
-
#
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
content=f"{prefix_prompt}\n\n{content}",
|
|
662
|
+
# Append workflow content to the agent's system message
|
|
663
|
+
# This ensures the context persists when agents are cloned
|
|
664
|
+
workflow_content = (
|
|
665
|
+
f"\n\n--- Workflow Memory ---\n{prefix_prompt}\n\n{content}"
|
|
431
666
|
)
|
|
432
667
|
|
|
433
|
-
|
|
668
|
+
# Update the original system message to include workflow
|
|
669
|
+
if agent._original_system_message is None:
|
|
670
|
+
logger.error(
|
|
671
|
+
f"Agent {agent.agent_id} has no system message. "
|
|
672
|
+
"Cannot append workflow memory to system message."
|
|
673
|
+
)
|
|
674
|
+
return (
|
|
675
|
+
"Error: Agent has no system message to append workflow to"
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
# Update the current system message
|
|
679
|
+
current_system_message = agent._system_message
|
|
680
|
+
if current_system_message is not None:
|
|
681
|
+
new_sys_content = (
|
|
682
|
+
current_system_message.content + workflow_content
|
|
683
|
+
)
|
|
684
|
+
agent._system_message = (
|
|
685
|
+
current_system_message.create_new_instance(new_sys_content)
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
# Replace the system message in memory
|
|
689
|
+
# Clear and re-initialize with updated system message
|
|
690
|
+
agent.memory.clear()
|
|
691
|
+
agent.update_memory(
|
|
692
|
+
agent._system_message, OpenAIBackendRole.SYSTEM
|
|
693
|
+
)
|
|
434
694
|
|
|
435
695
|
char_count = len(content)
|
|
436
696
|
log_msg = (
|
|
@@ -445,3 +705,100 @@ class ContextUtility:
|
|
|
445
705
|
error_msg = f"Failed to load markdown context to memory: {e}"
|
|
446
706
|
logger.error(error_msg)
|
|
447
707
|
return error_msg
|
|
708
|
+
|
|
709
|
+
def _filter_metadata_from_content(self, content: str) -> str:
|
|
710
|
+
r"""Filter out metadata section from markdown content.
|
|
711
|
+
|
|
712
|
+
Args:
|
|
713
|
+
content (str): The full markdown content including metadata.
|
|
714
|
+
|
|
715
|
+
Returns:
|
|
716
|
+
str: Content with metadata section removed.
|
|
717
|
+
"""
|
|
718
|
+
lines = content.split('\n')
|
|
719
|
+
filtered_lines = []
|
|
720
|
+
skip_metadata = False
|
|
721
|
+
|
|
722
|
+
for line in lines:
|
|
723
|
+
# Check if we're starting a metadata section
|
|
724
|
+
if line.strip() == "## Metadata":
|
|
725
|
+
skip_metadata = True
|
|
726
|
+
continue
|
|
727
|
+
|
|
728
|
+
# Check if we're starting a new section after metadata
|
|
729
|
+
if (
|
|
730
|
+
skip_metadata
|
|
731
|
+
and line.startswith("## ")
|
|
732
|
+
and "Metadata" not in line
|
|
733
|
+
):
|
|
734
|
+
skip_metadata = False
|
|
735
|
+
|
|
736
|
+
# Add line if we're not in metadata section
|
|
737
|
+
if not skip_metadata:
|
|
738
|
+
filtered_lines.append(line)
|
|
739
|
+
|
|
740
|
+
# Clean up any extra whitespace at the beginning
|
|
741
|
+
result = '\n'.join(filtered_lines).strip()
|
|
742
|
+
return result
|
|
743
|
+
|
|
744
|
+
# ========= SHARED SESSION MANAGEMENT METHODS =========
|
|
745
|
+
|
|
746
|
+
@classmethod
|
|
747
|
+
def get_workforce_shared(
|
|
748
|
+
cls, session_id: Optional[str] = None
|
|
749
|
+
) -> 'ContextUtility':
|
|
750
|
+
r"""Get or create shared workforce context utility with lazy init.
|
|
751
|
+
|
|
752
|
+
This method provides a centralized way to access shared context
|
|
753
|
+
utilities for workforce workflows, ensuring all workforce components
|
|
754
|
+
use the same session directory.
|
|
755
|
+
|
|
756
|
+
Args:
|
|
757
|
+
session_id (str, optional): Custom session ID. If None, uses the
|
|
758
|
+
default workforce session.
|
|
759
|
+
|
|
760
|
+
Returns:
|
|
761
|
+
ContextUtility: Shared context utility instance for workforce.
|
|
762
|
+
"""
|
|
763
|
+
if session_id is None:
|
|
764
|
+
# Use default workforce session
|
|
765
|
+
if cls._default_workforce_session is None:
|
|
766
|
+
camel_workdir = os.environ.get("CAMEL_WORKDIR")
|
|
767
|
+
if camel_workdir:
|
|
768
|
+
base_path = os.path.join(
|
|
769
|
+
camel_workdir, "workforce_workflows"
|
|
770
|
+
)
|
|
771
|
+
else:
|
|
772
|
+
base_path = "workforce_workflows"
|
|
773
|
+
|
|
774
|
+
cls._default_workforce_session = cls(
|
|
775
|
+
working_directory=base_path,
|
|
776
|
+
create_folder=False, # Don't create folder until needed
|
|
777
|
+
)
|
|
778
|
+
return cls._default_workforce_session
|
|
779
|
+
|
|
780
|
+
# Use specific session
|
|
781
|
+
if session_id not in cls._shared_sessions:
|
|
782
|
+
camel_workdir = os.environ.get("CAMEL_WORKDIR")
|
|
783
|
+
if camel_workdir:
|
|
784
|
+
base_path = os.path.join(camel_workdir, "workforce_workflows")
|
|
785
|
+
else:
|
|
786
|
+
base_path = "workforce_workflows"
|
|
787
|
+
|
|
788
|
+
cls._shared_sessions[session_id] = cls(
|
|
789
|
+
working_directory=base_path,
|
|
790
|
+
session_id=session_id,
|
|
791
|
+
create_folder=False, # Don't create folder until needed
|
|
792
|
+
)
|
|
793
|
+
return cls._shared_sessions[session_id]
|
|
794
|
+
|
|
795
|
+
@classmethod
|
|
796
|
+
def reset_shared_sessions(cls) -> None:
|
|
797
|
+
r"""Reset shared sessions (useful for testing).
|
|
798
|
+
|
|
799
|
+
This method clears all shared session instances, forcing new ones
|
|
800
|
+
to be created on next access. Primarily used for testing to ensure
|
|
801
|
+
clean state between tests.
|
|
802
|
+
"""
|
|
803
|
+
cls._shared_sessions.clear()
|
|
804
|
+
cls._default_workforce_session = None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
camel/__init__.py,sha256=
|
|
1
|
+
camel/__init__.py,sha256=Ayod-aBI4SOYLPkPisk9B8JRFy0vDqh5FNKIGpolDFA,899
|
|
2
2
|
camel/generators.py,sha256=JRqj9_m1PF4qT6UtybzTQ-KBT9MJQt18OAAYvQ_fr2o,13844
|
|
3
3
|
camel/human.py,sha256=Xg8x1cS5KK4bQ1SDByiHZnzsRpvRP-KZViNvmu38xo4,5475
|
|
4
4
|
camel/logger.py,sha256=WgEwael_eT6D-lVAKHpKIpwXSTjvLbny5jbV1Ab8lnA,5760
|
|
@@ -7,7 +7,7 @@ camel/agents/__init__.py,sha256=64weKqdvmpZcGWyVkO-OKASAmVUdrQjv60JApgPk_SA,1644
|
|
|
7
7
|
camel/agents/_types.py,sha256=MeFZzay2kJA6evALQ-MbBTKW-0lu_0wBuKsxzH_4gWI,1552
|
|
8
8
|
camel/agents/_utils.py,sha256=AR7Qqgbkmn4X2edYUQf1rdksGUyV5hm3iK1z-Dn0Mcg,6266
|
|
9
9
|
camel/agents/base.py,sha256=c4bJYL3G3Z41SaFdMPMn8ZjLdFiFaVOFO6EQIfuCVR8,1124
|
|
10
|
-
camel/agents/chat_agent.py,sha256=
|
|
10
|
+
camel/agents/chat_agent.py,sha256=ITd989GzaAd-FrJQ8QSnXFfGbZyWS973qYZUeKKaljc,186933
|
|
11
11
|
camel/agents/critic_agent.py,sha256=L6cTbYjyZB0DCa51tQ6LZLA6my8kHLC4nktHySH78H4,10433
|
|
12
12
|
camel/agents/deductive_reasoner_agent.py,sha256=6BZGaq1hR6hKJuQtOfoYQnk_AkZpw_Mr7mUy2MspQgs,13540
|
|
13
13
|
camel/agents/embodied_agent.py,sha256=XBxBu5ZMmSJ4B2U3Z7SMwvLlgp6yNpaBe8HNQmY9CZA,7536
|
|
@@ -82,7 +82,7 @@ camel/configs/watsonx_config.py,sha256=Ox_xZVCHp-42vKtWSWZtROt9rle7y2aNjVUYEXZ-A
|
|
|
82
82
|
camel/configs/yi_config.py,sha256=EJVp6SWX6XuQFMxqgpg-HnBPkr_HvsCJIgQiK5R-i1I,2720
|
|
83
83
|
camel/configs/zhipuai_config.py,sha256=RQrUrWFXKvyrXo8mbGeyUsal5YRbWCKAwU4s6_4yeu4,3560
|
|
84
84
|
camel/data_collectors/__init__.py,sha256=UWZya21xeJ6DvyLcf54XlYPg7ShOsNJmNR88kfRLmnA,924
|
|
85
|
-
camel/data_collectors/alpaca_collector.py,sha256=
|
|
85
|
+
camel/data_collectors/alpaca_collector.py,sha256=PgSDUPHOF7C_Ypw6AymQclV7xv-J_RBUJl7xXMTHO1A,5087
|
|
86
86
|
camel/data_collectors/base.py,sha256=Rn0aJBBvpMZYYTLT1yNjIalIvDuVVwOx6iawKlzocZQ,6708
|
|
87
87
|
camel/data_collectors/sharegpt_collector.py,sha256=Et5Q7imvnPdEDKBoTMJOchfTGHunHimFnUmQygRAeFU,7617
|
|
88
88
|
camel/datagen/__init__.py,sha256=EPF-eZ4rg7qbeSVZhfQ0iME0WDRSqRwBGbW-s0ZJ2EA,949
|
|
@@ -281,15 +281,15 @@ camel/societies/babyagi_playing.py,sha256=KbTdpHfZ2V8AripVck0bNTOyF-RSaMPCRARz3D
|
|
|
281
281
|
camel/societies/role_playing.py,sha256=0XScr3WfxX1QOC71RhBLmrcS5y2c7DMQB_mAFOHU34M,31421
|
|
282
282
|
camel/societies/workforce/__init__.py,sha256=bkTI-PE-MSK9AQ2V2gR6cR2WY-R7Jqy_NmXRtAoqo8o,920
|
|
283
283
|
camel/societies/workforce/base.py,sha256=z2DmbTP5LL5-aCAAqglznQqCLfPmnyM5zD3w6jjtsb8,2175
|
|
284
|
-
camel/societies/workforce/prompts.py,sha256=
|
|
284
|
+
camel/societies/workforce/prompts.py,sha256=I9MmLF-H_FwjDxWgTPBP8swzcPtG11aS3OZLzOF2NZQ,22039
|
|
285
285
|
camel/societies/workforce/role_playing_worker.py,sha256=Zm89lZTlV0T3o9C-DJ0HAV68Iq2Kdg8QqJRWs1TV9_A,10320
|
|
286
|
-
camel/societies/workforce/single_agent_worker.py,sha256=
|
|
287
|
-
camel/societies/workforce/structured_output_handler.py,sha256=
|
|
286
|
+
camel/societies/workforce/single_agent_worker.py,sha256=zASWmiZHEIqcUroD9vC1ZlqXaUlb7u2E1_StebNBuTQ,34501
|
|
287
|
+
camel/societies/workforce/structured_output_handler.py,sha256=RRp1p18Iss7gYdzOl9wAy1DB2A_oRvJ_qr5LGIGYVYc,18528
|
|
288
288
|
camel/societies/workforce/task_channel.py,sha256=rl0xSZg-8QIIHtXwC7f1GqESmNpdHJ_Jz8M524m5nEc,13238
|
|
289
|
-
camel/societies/workforce/utils.py,sha256=
|
|
289
|
+
camel/societies/workforce/utils.py,sha256=Q9_UvpxLVa9AK477WAlTqk9qcEFLGpvS-LOuKpE4oOI,11443
|
|
290
290
|
camel/societies/workforce/worker.py,sha256=MtUqYkTC9V-PIIRwSkKiB9w_YSu92iOpoha2rktEiQ0,6248
|
|
291
|
-
camel/societies/workforce/workforce.py,sha256=
|
|
292
|
-
camel/societies/workforce/workforce_logger.py,sha256=
|
|
291
|
+
camel/societies/workforce/workforce.py,sha256=jE6mkITgArrhtsxl5_yT4hh4b_Vz5N82oD8SKms2rgU,184360
|
|
292
|
+
camel/societies/workforce/workforce_logger.py,sha256=F8wC0QKwGNn5KcBRsq9A3wz6cZvqYdGGX3Li4iuJDoI,25355
|
|
293
293
|
camel/storages/__init__.py,sha256=RwpEyvxpMbJzVDZJJygeBg4AzyYMkTjjkfB53hTuqGo,2141
|
|
294
294
|
camel/storages/graph_storages/__init__.py,sha256=G29BNn651C0WTOpjCl4QnVM-4B9tcNh8DdmsCiONH8Y,948
|
|
295
295
|
camel/storages/graph_storages/base.py,sha256=uSe9jWuLudfm5jtfo6E-L_kNzITwK1_Ef-6L4HWw-JM,2852
|
|
@@ -336,7 +336,7 @@ camel/toolkits/bohrium_toolkit.py,sha256=453t-m0h0IGjurG6tCHUejGzfRAN2SAkhIoY8V-
|
|
|
336
336
|
camel/toolkits/browser_toolkit.py,sha256=Ntn_LmCrhqqIBWq9HtiIKw-M0cL5ebn74Ej1GBoZiC8,44400
|
|
337
337
|
camel/toolkits/browser_toolkit_commons.py,sha256=uuc1V5tN3YJmTSe6NHAVJqwsL4iYD7IiSZWxPLYW67A,22196
|
|
338
338
|
camel/toolkits/code_execution.py,sha256=3LoSgKdIMlB3fMr7qFuFXt_9QXnTXS8pBfcld580N-k,6785
|
|
339
|
-
camel/toolkits/context_summarizer_toolkit.py,sha256=
|
|
339
|
+
camel/toolkits/context_summarizer_toolkit.py,sha256=P6Ds2xKcYrT0K8g5bbHcG49-QfZNlTOQi8Ahdv2OaIg,25776
|
|
340
340
|
camel/toolkits/craw4ai_toolkit.py,sha256=av8mqY68QgMSm27htnSdq0aqE6z3yWMVDSrNafQ6ORw,3298
|
|
341
341
|
camel/toolkits/dappier_toolkit.py,sha256=OEHOYXX_oXhgbVtWYAy13nO9uXf9i5qEXSwY4PexNFg,8194
|
|
342
342
|
camel/toolkits/data_commons_toolkit.py,sha256=aHZUSL1ACpnYGaf1rE2csVKTmXTmN8lMGRUBYhZ_YEk,14168
|
|
@@ -455,9 +455,9 @@ camel/toolkits/open_api_specs/web_scraper/paths/__init__.py,sha256=OKCZrQCDwaWtX
|
|
|
455
455
|
camel/toolkits/open_api_specs/web_scraper/paths/scraper.py,sha256=aWy1_ppV4NVVEZfnbN3tu9XA9yAPAC9bRStJ5JuXMRU,1117
|
|
456
456
|
camel/toolkits/terminal_toolkit/__init__.py,sha256=yE66haKm-NwoNJwtnCmcRpANtWxQB_dZoD8O5iqXt_Y,786
|
|
457
457
|
camel/toolkits/terminal_toolkit/terminal_toolkit.py,sha256=Mp7C41d_T3guUNU7iXXOFKLNopTUyNGckzQ0JDCQ9og,36784
|
|
458
|
-
camel/toolkits/terminal_toolkit/utils.py,sha256=
|
|
458
|
+
camel/toolkits/terminal_toolkit/utils.py,sha256=qUKVUwe5lbXVV7hJizSdJwZqFZdl_Xpyb08aKDNUetE,17293
|
|
459
459
|
camel/types/__init__.py,sha256=EOmWlqS7aE5cB51_Vv7vHUexKeBbx9FSsfynl5vKjwo,2565
|
|
460
|
-
camel/types/enums.py,sha256=
|
|
460
|
+
camel/types/enums.py,sha256=BLGlUTtqee-ov6Au5K0NKX_6_ORdUIQ6YwYRx7L8uGU,70426
|
|
461
461
|
camel/types/mcp_registries.py,sha256=dl4LgYtSaUhsqAKpz28k_SA9La11qxqBvDLaEuyzrFE,4971
|
|
462
462
|
camel/types/openai_types.py,sha256=m7oWb8nWYWOAwBRY1mP9mS9RVufXeDVj-fGvHAhXuMU,2120
|
|
463
463
|
camel/types/unified_model_type.py,sha256=gs_Wr0acrqn81kjyd6zm_OzCUol2d0QQH1-QXsuxVxo,6196
|
|
@@ -467,7 +467,7 @@ camel/utils/__init__.py,sha256=qQeMHZJ8Bbgpm4tBu-LWc_P3iFjXBlVfALdKTiD_s8I,3305
|
|
|
467
467
|
camel/utils/async_func.py,sha256=KqoktGSWjZBuAMQ2CV0X6FRgHGlzCKLfeaWvp-f1Qz8,1568
|
|
468
468
|
camel/utils/commons.py,sha256=OJxvdnpfUColR0nM4ounrt6ygszvOin2jp8NA08jTGw,37843
|
|
469
469
|
camel/utils/constants.py,sha256=cqnxmpUeOwrtsR-tRO4bbOc6ZP19TLj7avjm3FONMJs,1410
|
|
470
|
-
camel/utils/context_utils.py,sha256=
|
|
470
|
+
camel/utils/context_utils.py,sha256=NonmuqX7W1IzxVOvyd02Ad_VJDvDYLqujTwEVXQkX64,30271
|
|
471
471
|
camel/utils/deduplication.py,sha256=UHikAtOW1TTDunf2t_wa2kFbmkrXWf7HfOKwLvwCxzo,8958
|
|
472
472
|
camel/utils/filename.py,sha256=HYNc1wbSCgNR1CN21cwHxdAhpnsf5ySJ6jUDfeqOK20,2532
|
|
473
473
|
camel/utils/langfuse.py,sha256=OowR6A790XG-b0UHiTYduYvS18PvSGFdmqki2Poogo0,8578
|
|
@@ -487,7 +487,7 @@ camel/verifiers/math_verifier.py,sha256=tA1D4S0sm8nsWISevxSN0hvSVtIUpqmJhzqfbuMo
|
|
|
487
487
|
camel/verifiers/models.py,sha256=GdxYPr7UxNrR1577yW4kyroRcLGfd-H1GXgv8potDWU,2471
|
|
488
488
|
camel/verifiers/physics_verifier.py,sha256=c1grrRddcrVN7szkxhv2QirwY9viIRSITWeWFF5HmLs,30187
|
|
489
489
|
camel/verifiers/python_verifier.py,sha256=ogTz77wODfEcDN4tMVtiSkRQyoiZbHPY2fKybn59lHw,20558
|
|
490
|
-
camel_ai-0.2.
|
|
491
|
-
camel_ai-0.2.
|
|
492
|
-
camel_ai-0.2.
|
|
493
|
-
camel_ai-0.2.
|
|
490
|
+
camel_ai-0.2.77.dist-info/METADATA,sha256=HJMbtnxJz16ltycHjp7n1NYTWuaZE8-dS3JMR_wKKL4,55190
|
|
491
|
+
camel_ai-0.2.77.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
492
|
+
camel_ai-0.2.77.dist-info/licenses/LICENSE,sha256=id0nB2my5kG0xXeimIu5zZrbHLS6EQvxvkKkzIHaT2k,11343
|
|
493
|
+
camel_ai-0.2.77.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|