@aj-archipelago/cortex 1.4.2 → 1.4.4
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.
- package/README.md +1 -0
- package/config.js +1 -1
- package/helper-apps/cortex-autogen2/.dockerignore +1 -0
- package/helper-apps/cortex-autogen2/Dockerfile +6 -10
- package/helper-apps/cortex-autogen2/Dockerfile.worker +2 -0
- package/helper-apps/cortex-autogen2/agents.py +203 -2
- package/helper-apps/cortex-autogen2/main.py +1 -1
- package/helper-apps/cortex-autogen2/pyproject.toml +12 -0
- package/helper-apps/cortex-autogen2/requirements.txt +14 -0
- package/helper-apps/cortex-autogen2/services/redis_publisher.py +1 -1
- package/helper-apps/cortex-autogen2/services/run_analyzer.py +1 -1
- package/helper-apps/cortex-autogen2/task_processor.py +431 -229
- package/helper-apps/cortex-autogen2/test_entity_fetcher.py +305 -0
- package/helper-apps/cortex-autogen2/tests/README.md +240 -0
- package/helper-apps/cortex-autogen2/tests/TEST_REPORT.md +342 -0
- package/helper-apps/cortex-autogen2/tests/__init__.py +8 -0
- package/helper-apps/cortex-autogen2/tests/analysis/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/tests/analysis/improvement_suggester.py +224 -0
- package/helper-apps/cortex-autogen2/tests/analysis/trend_analyzer.py +211 -0
- package/helper-apps/cortex-autogen2/tests/cli/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/tests/cli/run_tests.py +296 -0
- package/helper-apps/cortex-autogen2/tests/collectors/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/tests/collectors/log_collector.py +252 -0
- package/helper-apps/cortex-autogen2/tests/collectors/progress_collector.py +182 -0
- package/helper-apps/cortex-autogen2/tests/conftest.py +15 -0
- package/helper-apps/cortex-autogen2/tests/database/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/tests/database/repository.py +501 -0
- package/helper-apps/cortex-autogen2/tests/database/schema.sql +108 -0
- package/helper-apps/cortex-autogen2/tests/evaluators/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/tests/evaluators/llm_scorer.py +294 -0
- package/helper-apps/cortex-autogen2/tests/evaluators/prompts.py +250 -0
- package/helper-apps/cortex-autogen2/tests/evaluators/wordcloud_validator.py +168 -0
- package/helper-apps/cortex-autogen2/tests/metrics/__init__.py +1 -0
- package/helper-apps/cortex-autogen2/tests/metrics/collector.py +155 -0
- package/helper-apps/cortex-autogen2/tests/orchestrator.py +576 -0
- package/helper-apps/cortex-autogen2/tests/test_cases.yaml +279 -0
- package/helper-apps/cortex-autogen2/tests/test_data.db +0 -0
- package/helper-apps/cortex-autogen2/tests/utils/__init__.py +3 -0
- package/helper-apps/cortex-autogen2/tests/utils/connectivity.py +112 -0
- package/helper-apps/cortex-autogen2/tools/azure_blob_tools.py +74 -24
- package/helper-apps/cortex-autogen2/tools/entity_api_registry.json +38 -0
- package/helper-apps/cortex-autogen2/tools/file_tools.py +1 -1
- package/helper-apps/cortex-autogen2/tools/search_tools.py +436 -238
- package/helper-apps/cortex-file-handler/package-lock.json +2 -2
- package/helper-apps/cortex-file-handler/package.json +1 -1
- package/helper-apps/cortex-file-handler/scripts/setup-test-containers.js +4 -5
- package/helper-apps/cortex-file-handler/src/blobHandler.js +36 -144
- package/helper-apps/cortex-file-handler/src/services/FileConversionService.js +5 -3
- package/helper-apps/cortex-file-handler/src/services/storage/AzureStorageProvider.js +34 -1
- package/helper-apps/cortex-file-handler/src/services/storage/GCSStorageProvider.js +22 -0
- package/helper-apps/cortex-file-handler/src/services/storage/LocalStorageProvider.js +28 -1
- package/helper-apps/cortex-file-handler/src/services/storage/StorageFactory.js +29 -4
- package/helper-apps/cortex-file-handler/src/services/storage/StorageProvider.js +11 -0
- package/helper-apps/cortex-file-handler/src/services/storage/StorageService.js +1 -1
- package/helper-apps/cortex-file-handler/tests/blobHandler.test.js +3 -2
- package/helper-apps/cortex-file-handler/tests/checkHashShortLived.test.js +8 -1
- package/helper-apps/cortex-file-handler/tests/containerConversionFlow.test.js +5 -2
- package/helper-apps/cortex-file-handler/tests/containerNameParsing.test.js +14 -7
- package/helper-apps/cortex-file-handler/tests/containerParameterFlow.test.js +5 -2
- package/helper-apps/cortex-file-handler/tests/storage/StorageFactory.test.js +31 -19
- package/lib/entityConstants.js +3 -0
- package/package.json +2 -2
- package/pathways/system/entity/sys_entity_agent.js +2 -1
- package/pathways/system/entity/tools/sys_tool_codingagent.js +2 -2
- package/pathways/system/workspaces/workspace_applet_edit.js +551 -29
- package/server/modelExecutor.js +4 -0
- package/server/plugins/claude4VertexPlugin.js +540 -0
- package/server/plugins/openAiWhisperPlugin.js +43 -2
- package/tests/integration/rest/vendors/claude_streaming.test.js +121 -0
- package/tests/unit/plugins/claude4VertexPlugin.test.js +462 -0
- package/tests/unit/plugins/claude4VertexToolConversion.test.js +413 -0
- package/helper-apps/cortex-autogen/.funcignore +0 -8
- package/helper-apps/cortex-autogen/Dockerfile +0 -10
- package/helper-apps/cortex-autogen/OAI_CONFIG_LIST +0 -6
- package/helper-apps/cortex-autogen/agents.py +0 -493
- package/helper-apps/cortex-autogen/agents_extra.py +0 -14
- package/helper-apps/cortex-autogen/config.py +0 -18
- package/helper-apps/cortex-autogen/data_operations.py +0 -29
- package/helper-apps/cortex-autogen/function_app.py +0 -44
- package/helper-apps/cortex-autogen/host.json +0 -15
- package/helper-apps/cortex-autogen/main.py +0 -38
- package/helper-apps/cortex-autogen/prompts.py +0 -196
- package/helper-apps/cortex-autogen/prompts_extra.py +0 -5
- package/helper-apps/cortex-autogen/requirements.txt +0 -9
- package/helper-apps/cortex-autogen/search.py +0 -85
- package/helper-apps/cortex-autogen/test.sh +0 -40
- package/helper-apps/cortex-autogen/tools/sasfileuploader.py +0 -66
- package/helper-apps/cortex-autogen/utils.py +0 -88
- package/helper-apps/cortex-autogen2/DigiCertGlobalRootCA.crt.pem +0 -22
- package/helper-apps/cortex-autogen2/poetry.lock +0 -3652
- package/testrun.log +0 -35371
package/README.md
CHANGED
|
@@ -540,6 +540,7 @@ Models are configured in the `models` section of the config. Each model can have
|
|
|
540
540
|
- `GEMINI-1.5-CHAT`: For Gemini 1.5 Pro chat models
|
|
541
541
|
- `GEMINI-1.5-VISION`: For Gemini vision models (including 2.0 Flash experimental)
|
|
542
542
|
- `CLAUDE-3-VERTEX`: For Claude-3 and 3.5 models (Haiku, Opus, Sonnet)
|
|
543
|
+
- `CLAUDE-4-VERTEX`: For Claude-4 models (Sonnet 4, Sonnet 4.5, Opus 4.1, Haiku 4.5) with enhanced support for PDFs and text files
|
|
543
544
|
- `GROK-VISION`: For XAI Grok models (Grok-3, Grok-4, fast-reasoning, code-fast) with multimodal/vision and reasoning
|
|
544
545
|
- `AZURE-TRANSLATE`: For Azure translation services
|
|
545
546
|
|
package/config.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.venv
|
|
@@ -23,10 +23,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive \
|
|
|
23
23
|
fonts-noto-core fonts-noto-ui-core \
|
|
24
24
|
fonts-noto-color-emoji fonts-noto-cjk \
|
|
25
25
|
fonts-dejavu fonts-dejavu-core fonts-dejavu-extra \
|
|
26
|
-
fonts-freefont-ttf fonts-
|
|
27
|
-
# ─ Arabic fonts specifically for matplotlib/reportlab
|
|
28
|
-
fonts-arabeyes fonts-farsiweb fonts-kacst fonts-kacst-one \
|
|
29
|
-
fonts-hosny-amiri fonts-sil-scheherazade fonts-sil-lateef \
|
|
26
|
+
fonts-freefont-ttf fonts-liberation \
|
|
30
27
|
# ─ Build chain for packages that still compile C/C++
|
|
31
28
|
build-essential gcc g++ make \
|
|
32
29
|
# ─ libmagic for `python-magic`
|
|
@@ -40,22 +37,21 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive \
|
|
|
40
37
|
# ─ Computer-vision helpers sometimes needed by OpenCV
|
|
41
38
|
libsm6 libxext6 libglib2.0-0 \
|
|
42
39
|
# ─ HDF5 stack for `h5py`
|
|
43
|
-
libhdf5-
|
|
40
|
+
libhdf5-dev hdf5-tools \
|
|
44
41
|
# ─ Cairo / Pango / GDK-PixBuf for SVG->PNG rendering (CairoSVG optional deps)
|
|
45
42
|
libcairo2 libcairo2-dev \
|
|
46
43
|
libpango-1.0-0 libpangoft2-1.0-0 libpangocairo-1.0-0 \
|
|
47
44
|
libgdk-pixbuf-2.0-0 libgdk-pixbuf2.0-bin \
|
|
48
|
-
# ─ GDAL for GIS formats (and Python bindings)
|
|
49
|
-
gdal-bin libgdal-dev python3-gdal \
|
|
50
45
|
# ─ 7-Zip & RAR extractors (for patool / rarfile fall-back)
|
|
51
46
|
unrar-free \
|
|
47
|
+
# ─ LibreOffice for PPTX → PDF conversion (slide previews)
|
|
48
|
+
libreoffice-core libreoffice-writer libreoffice-impress \
|
|
49
|
+
# ─ Poppler utilities for PDF → PNG conversion (pdf2image)
|
|
50
|
+
poppler-utils \
|
|
52
51
|
# ─ Clean-up
|
|
53
52
|
&& apt-get clean \
|
|
54
53
|
&& rm -rf /var/lib/apt/lists/*
|
|
55
54
|
|
|
56
|
-
# Allow GDAL Python wheels to find headers
|
|
57
|
-
ENV CPLUS_INCLUDE_PATH=/usr/include/gdal
|
|
58
|
-
ENV C_INCLUDE_PATH=/usr/include/gdal
|
|
59
55
|
|
|
60
56
|
# ------------------------------------------------------------------------------
|
|
61
57
|
# 3. Python dependencies
|
|
@@ -8,6 +8,43 @@ from tools.azure_blob_tools import upload_file_to_azure_blob
|
|
|
8
8
|
#AGENTS
|
|
9
9
|
MAGENTIC_ONE_CODER_DESCRIPTION = "A helpful and general-purpose AI assistant that has strong language skills, Python skills, and Linux command line skills."
|
|
10
10
|
|
|
11
|
+
def _safe_upload_wrapper(file_path: str, blob_name: str = None) -> str:
|
|
12
|
+
"""
|
|
13
|
+
Wrapper around upload_file_to_azure_blob that ensures the JSON response is wrapped in markdown.
|
|
14
|
+
This prevents AutoGen from re-parsing the JSON and losing the 'type' field in message content.
|
|
15
|
+
"""
|
|
16
|
+
result_json = upload_file_to_azure_blob(file_path, blob_name)
|
|
17
|
+
|
|
18
|
+
# CRITICAL: Wrap JSON in markdown code block to prevent AutoGen re-parsing
|
|
19
|
+
if result_json.strip().startswith('{'):
|
|
20
|
+
return f"```json\n{result_json}\n```"
|
|
21
|
+
return result_json
|
|
22
|
+
|
|
23
|
+
def _wrap_json_result(result: str) -> str:
|
|
24
|
+
"""
|
|
25
|
+
Generic wrapper for ANY tool that returns JSON strings.
|
|
26
|
+
Wraps JSON in markdown to prevent AutoGen from re-parsing and losing message structure.
|
|
27
|
+
|
|
28
|
+
CRITICAL PATTERN FOR ALL TOOL DEVELOPERS:
|
|
29
|
+
When a tool returns JSON (via json.dumps()), wrap it in markdown:
|
|
30
|
+
- return json.dumps({...}) # ❌ AutoGen will re-parse
|
|
31
|
+
- return f"```json\n{json.dumps({...})}\n```" # ✅ AutoGen treats as text
|
|
32
|
+
|
|
33
|
+
Or use this wrapper:
|
|
34
|
+
- return _wrap_json_result(json.dumps({...}))
|
|
35
|
+
|
|
36
|
+
This prevents the "Missing required parameter: 'messages[X].content[0].type'" error
|
|
37
|
+
because AutoGen won't attempt to re-parse the JSON into a dict.
|
|
38
|
+
"""
|
|
39
|
+
if not result:
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
result_str = str(result).strip()
|
|
43
|
+
# Wrap any JSON-like string in markdown
|
|
44
|
+
if result_str.startswith(('{', '[')):
|
|
45
|
+
return f"```json\n{result_str}\n```"
|
|
46
|
+
return result
|
|
47
|
+
|
|
11
48
|
MAGENTIC_ONE_CODER_SYSTEM_MESSAGE = """You are a helpful AI assistant.
|
|
12
49
|
Solve tasks using your coding and language skills.
|
|
13
50
|
In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.
|
|
@@ -20,7 +57,7 @@ If the result indicates there is an error, fix the error and output the code aga
|
|
|
20
57
|
When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible."""
|
|
21
58
|
|
|
22
59
|
|
|
23
|
-
async def get_agents(default_model_client, big_model_client, small_model_client, request_work_dir: Optional[str] = None):
|
|
60
|
+
async def get_agents(default_model_client, big_model_client, small_model_client, request_work_dir: Optional[str] = None, planner_learnings: Optional[str] = None, task_context: Optional[str] = None):
|
|
24
61
|
|
|
25
62
|
# Resolve work dir (prefer per-request dir if provided or from env)
|
|
26
63
|
work_dir = request_work_dir or os.getenv("CORTEX_WORK_DIR", "/home/site/wwwroot/coding")
|
|
@@ -39,7 +76,7 @@ async def get_agents(default_model_client, big_model_client, small_model_client,
|
|
|
39
76
|
code_executor = LocalCommandLineCodeExecutor(work_dir=work_dir, timeout=300)
|
|
40
77
|
|
|
41
78
|
#TOOLS
|
|
42
|
-
upload_file_to_cloud_tool = FunctionTool(
|
|
79
|
+
upload_file_to_cloud_tool = FunctionTool(_safe_upload_wrapper, description="Upload files to the cloud. You must use absolute path to reference local files.")
|
|
43
80
|
|
|
44
81
|
coder_agent = AssistantAgent(
|
|
45
82
|
"coder_agent",
|
|
@@ -61,6 +98,144 @@ async def get_agents(default_model_client, big_model_client, small_model_client,
|
|
|
61
98
|
Code executor working directory is: {work_dir}
|
|
62
99
|
So you can only access files in this directory.
|
|
63
100
|
Always use absolute path to reference files as current directory might be different from the one you think it is.
|
|
101
|
+
|
|
102
|
+
=== POWERPOINT PRESENTATION CREATION (python-pptx) ===
|
|
103
|
+
**When creating .pptx presentations, follow these CRITICAL patterns:**
|
|
104
|
+
|
|
105
|
+
1. **Image Preprocessing (BEFORE adding to presentation):**
|
|
106
|
+
- Use PIL to convert WEBP, TIFF, and other unsupported formats to PNG
|
|
107
|
+
- Define supported formats: {'png', 'jpg', 'jpeg', 'gif', 'bmp'}
|
|
108
|
+
- For each unsupported image, open with PIL and save as PNG
|
|
109
|
+
- Handle RGBA images by converting to RGB with white background
|
|
110
|
+
|
|
111
|
+
2. **Build Presentation Structure:**
|
|
112
|
+
- Import: `from pptx import Presentation; from pptx.util import Inches, Pt`
|
|
113
|
+
- Create presentation: `prs = Presentation()`
|
|
114
|
+
- Set dimensions: `prs.slide_width = Inches(10); prs.slide_height = Inches(7.5)`
|
|
115
|
+
- Track slide count to validate before saving
|
|
116
|
+
- Use `prs.slide_layouts[6]` (blank) for maximum control over image placement
|
|
117
|
+
|
|
118
|
+
3. **Add Slides:**
|
|
119
|
+
- Title Slide: `slide = prs.slides.add_slide(prs.slide_layouts[0])`
|
|
120
|
+
- Content Slide: `slide = prs.slides.add_slide(prs.slide_layouts[1])`
|
|
121
|
+
- Image Slide: Use blank layout `prs.slide_layouts[6]` then `slide.shapes.add_picture(path, left, top, width, height)`
|
|
122
|
+
- Always wrap image operations in try/except and add text fallback if image fails
|
|
123
|
+
|
|
124
|
+
4. **Save with Validation:**
|
|
125
|
+
- ALWAYS check: `if len(prs.slides) == 0: raise ValueError("No slides!")`
|
|
126
|
+
- Save to CORTEX_WORK_DIR: `output_path = os.path.join(os.environ['CORTEX_WORK_DIR'], 'Title.pptx')`
|
|
127
|
+
- Use descriptive filename (NOT draft.pptx)
|
|
128
|
+
- After save, verify file size: `os.path.getsize(output_path) > 10000` (empty files are tiny)
|
|
129
|
+
- Print success: `print(f"📁 Ready for upload: {{output_path}}")`
|
|
130
|
+
|
|
131
|
+
**CRITICAL CHECKLIST:**
|
|
132
|
+
✅ Image format validation and conversion BEFORE adding
|
|
133
|
+
✅ Slide count > 0 before saving
|
|
134
|
+
✅ Safe image dimensions (Inches(9) width for 10" slides)
|
|
135
|
+
✅ Error handling with text fallbacks
|
|
136
|
+
✅ File size validation after save
|
|
137
|
+
✅ Use Inches() for measurements, NOT pixels
|
|
138
|
+
✅ Explicit presentation dimensions
|
|
139
|
+
✅ Proper output path in CORTEX_WORK_DIR
|
|
140
|
+
|
|
141
|
+
=== CRITICAL: FILE AUTO-DISCOVERY & UPLOAD ===
|
|
142
|
+
After you save files to CORTEX_WORK_DIR, the system AUTOMATICALLY:
|
|
143
|
+
1. Scans CORTEX_WORK_DIR for deliverable files (.pptx, .ppt, .csv, .png, .jpg, .pdf, .zip)
|
|
144
|
+
2. For .pptx files specifically: **picks the SINGLE LARGEST file** (assumes most complete)
|
|
145
|
+
3. Uploads that file to Azure Blob Storage
|
|
146
|
+
4. Provides URLs to the presenter
|
|
147
|
+
|
|
148
|
+
**CONSEQUENCE**: If your PowerPoint creation:
|
|
149
|
+
- Fails silently → no .pptx file exists → nothing gets presented
|
|
150
|
+
- Creates an empty file → small file size → might not be picked OR picked but empty
|
|
151
|
+
- Crashes before saving → no file → nothing presented
|
|
152
|
+
|
|
153
|
+
**YOUR RESPONSIBILITY**:
|
|
154
|
+
- ALWAYS validate that prs.slides has content before saving
|
|
155
|
+
- Print BOTH status AND file size: `print(f"✅ PPTX saved: {{path}} ({{os.path.getsize(path)}} bytes)")`
|
|
156
|
+
- On error, print explicit error: `print(f"❌ CRITICAL: Failed to create PPTX: {{error}}")`
|
|
157
|
+
- Never silently fail - ALWAYS log what happened
|
|
158
|
+
- Test file size > 50000 bytes for any real PowerPoint (empty files are 5-10KB)
|
|
159
|
+
|
|
160
|
+
=== COMPLETE PPTX EXAMPLE (COPY-PASTE READY) ===
|
|
161
|
+
```python
|
|
162
|
+
import os
|
|
163
|
+
import glob
|
|
164
|
+
from PIL import Image
|
|
165
|
+
from pptx import Presentation
|
|
166
|
+
from pptx.util import Inches, Pt
|
|
167
|
+
|
|
168
|
+
# Step 1: Preprocess images
|
|
169
|
+
work_dir = os.environ['CORTEX_WORK_DIR']
|
|
170
|
+
supported_formats = {'png', 'jpg', 'jpeg', 'gif', 'bmp'}
|
|
171
|
+
image_dir = os.path.join(work_dir, 'assets')
|
|
172
|
+
|
|
173
|
+
if os.path.isdir(image_dir):
|
|
174
|
+
for img_file in glob.glob(os.path.join(image_dir, '*')):
|
|
175
|
+
ext = os.path.splitext(img_file)[1].lower().lstrip('.')
|
|
176
|
+
if ext not in supported_formats and ext:
|
|
177
|
+
try:
|
|
178
|
+
with Image.open(img_file) as img:
|
|
179
|
+
if img.mode in ('RGBA', 'LA'):
|
|
180
|
+
rgb_img = Image.new('RGB', img.size, (255, 255, 255))
|
|
181
|
+
rgb_img.paste(img, mask=img.split()[-1])
|
|
182
|
+
img = rgb_img
|
|
183
|
+
png_path = os.path.splitext(img_file)[0] + '.png'
|
|
184
|
+
img.save(png_path, 'PNG')
|
|
185
|
+
os.remove(img_file)
|
|
186
|
+
print(f"✅ Converted {{os.path.basename(img_file)}} to PNG")
|
|
187
|
+
except Exception as e:
|
|
188
|
+
print(f"⚠️ Skipping {{img_file}}: {{e}}")
|
|
189
|
+
|
|
190
|
+
# Step 2: Create presentation
|
|
191
|
+
prs = Presentation()
|
|
192
|
+
prs.slide_width = Inches(10)
|
|
193
|
+
prs.slide_height = Inches(7.5)
|
|
194
|
+
slide_count = 0
|
|
195
|
+
|
|
196
|
+
# Title slide
|
|
197
|
+
title_slide = prs.slides.add_slide(prs.slide_layouts[0])
|
|
198
|
+
title_slide.shapes.title.text = "Your Title"
|
|
199
|
+
title_slide.placeholders[1].text = "Subtitle"
|
|
200
|
+
slide_count += 1
|
|
201
|
+
|
|
202
|
+
# Content slides with validation
|
|
203
|
+
image_files = sorted(glob.glob(os.path.join(image_dir, '*.png')))
|
|
204
|
+
for idx, img_path in enumerate(image_files[:10]): # Limit to 10 images
|
|
205
|
+
try:
|
|
206
|
+
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
|
207
|
+
left = Inches(0.5)
|
|
208
|
+
top = Inches(0.5)
|
|
209
|
+
height = Inches(6)
|
|
210
|
+
pic = slide.shapes.add_picture(img_path, left, top, height=height)
|
|
211
|
+
slide_count += 1
|
|
212
|
+
except Exception as e:
|
|
213
|
+
print(f"⚠️ Failed to add image {{idx}}: {{e}}")
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
# Validate before save
|
|
217
|
+
if slide_count == 0:
|
|
218
|
+
print("❌ ERROR: No slides were created!")
|
|
219
|
+
raise ValueError("Empty presentation")
|
|
220
|
+
|
|
221
|
+
# Step 3: Save with validation
|
|
222
|
+
output_path = os.path.join(work_dir, 'MyPresentation.pptx')
|
|
223
|
+
prs.save(output_path)
|
|
224
|
+
|
|
225
|
+
# Step 4: Verify
|
|
226
|
+
if os.path.exists(output_path):
|
|
227
|
+
size = os.path.getsize(output_path)
|
|
228
|
+
if size > 50000:
|
|
229
|
+
print(f"✅ PPTX saved: {{output_path}} ({{size}} bytes)")
|
|
230
|
+
print(f"📁 Ready for upload: {{output_path}}")
|
|
231
|
+
else:
|
|
232
|
+
print(f"❌ ERROR: PPTX too small ({{size}} bytes) - probably empty!")
|
|
233
|
+
else:
|
|
234
|
+
print(f"❌ ERROR: PPTX file was not created!")
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**AFTER SAVING FILES**: Immediately mention that file_cloud_uploader_agent should take over:
|
|
238
|
+
"I have saved the files. Now file_cloud_uploader_agent should upload them to the cloud."
|
|
64
239
|
""",
|
|
65
240
|
)
|
|
66
241
|
|
|
@@ -122,6 +297,19 @@ async def get_agents(default_model_client, big_model_client, small_model_client,
|
|
|
122
297
|
**DO NOT provide information about packaging, dependencies, or development workflows.**
|
|
123
298
|
Your output is for a non-technical end-user viewing it in a React app.
|
|
124
299
|
**CRITICAL: ONLY use URLs for any files (images, videos, documents, etc.) that are explicitly provided in the `UPLOADED_FILES_SAS_URLS` or directly within the `RESULT` content from other agents, specifically from the `file_cloud_uploader_agent`. If a valid, real URL is not provided, you MUST NOT include any placeholder, fake, or fabricated URLs. NEVER hallucinate or fabricate any links or content.**
|
|
300
|
+
|
|
301
|
+
=== CRITICAL URL VALIDATION (MANDATORY) ===
|
|
302
|
+
**Before creating your response, STOP and check:**
|
|
303
|
+
1. Look at `UPLOADED_FILES_SAS_URLS` - is it empty `{}` or does it contain placeholder tokens like 'sas_token', 'skoid', 'sktid'?
|
|
304
|
+
2. If UPLOADED_FILES_SAS_URLS is empty OR contains only placeholder/fake tokens:
|
|
305
|
+
**DO NOT ATTEMPT TO CREATE FAKE URLS**
|
|
306
|
+
Instead, respond: "⚠️ SYSTEM STATUS: Files are still being processed. Please wait for upload completion."
|
|
307
|
+
Then list what files are expected based on UPLOADED_FILES_LIST
|
|
308
|
+
3. If UPLOADED_FILES_SAS_URLS contains REAL Azure blob URLs (with format: https://ACCOUNT.blob.core.windows.net/CONTAINER/FILE?sv=...&sig=REAL_TOKEN&se=...):
|
|
309
|
+
You may proceed to present with those URLs
|
|
310
|
+
|
|
311
|
+
**DO NOT GUESS, INTERPOLATE, OR HALLUCINATE URLs EVER.**
|
|
312
|
+
**A fake URL is worse than no URL at all.**
|
|
125
313
|
"""
|
|
126
314
|
)
|
|
127
315
|
|
|
@@ -131,6 +319,19 @@ async def get_agents(default_model_client, big_model_client, small_model_client,
|
|
|
131
319
|
tools=[upload_file_to_cloud_tool],
|
|
132
320
|
description="A helpful assistant that can upload files to the cloud.",
|
|
133
321
|
system_message=f"""You are a helpful assistant that can upload files to the cloud.
|
|
322
|
+
Your PRIMARY RESPONSIBILITY: After ANY code has been executed or any file-based task is completed,
|
|
323
|
+
you MUST immediately scan {work_dir} for ALL deliverable files (.pptx, .pdf, .csv, .png, .jpg, .zip, .json, .txt, .md).
|
|
324
|
+
|
|
325
|
+
CRITICAL: Do NOT wait to be asked. Do NOT wait for explicit file references.
|
|
326
|
+
Simply list all files in {work_dir} and upload EVERY one of them to the cloud.
|
|
327
|
+
|
|
328
|
+
For each file found:
|
|
329
|
+
1. Upload it using your upload tool
|
|
330
|
+
2. Report the cloud URL
|
|
331
|
+
3. Confirm success
|
|
332
|
+
|
|
333
|
+
This ensures that NO files are left behind and the presenter always has access to deliverables.
|
|
334
|
+
|
|
134
335
|
Upload referenced files to the cloud.
|
|
135
336
|
Use your tool to upload the files.
|
|
136
337
|
User does not have local access to the files so you must upload them to the cloud and provide the url.
|
|
@@ -72,7 +72,7 @@ async def main():
|
|
|
72
72
|
decoded_content = base64.b64decode(raw_content).decode('utf-8')
|
|
73
73
|
task_data = json.loads(decoded_content)
|
|
74
74
|
except (json.JSONDecodeError, TypeError, ValueError) as e:
|
|
75
|
-
logger.
|
|
75
|
+
logger.debug(f"Base64 decode failed; falling back to raw JSON: {e}")
|
|
76
76
|
try:
|
|
77
77
|
task_data = json.loads(raw_content)
|
|
78
78
|
except json.JSONDecodeError as e2:
|
|
@@ -23,6 +23,8 @@ openpyxl = "^3.1.2"
|
|
|
23
23
|
xlrd = "^2.0.1"
|
|
24
24
|
python-pptx = "^0.6.23"
|
|
25
25
|
odfpy = "^1.4.1"
|
|
26
|
+
pdf2image = "^1.16.3"
|
|
27
|
+
python-pptx-interface = "^0.0.14"
|
|
26
28
|
|
|
27
29
|
# Infra / networking / AI you already had
|
|
28
30
|
autogen-agentchat = { extras = ["openai"], version = "^0.7.4" }
|
|
@@ -41,11 +43,21 @@ playwright = "^1.54.0"
|
|
|
41
43
|
markitdown = "^0.1.2"
|
|
42
44
|
aiofiles = "^24.1.0"
|
|
43
45
|
aiohttp = "^3.12.14"
|
|
46
|
+
numpy = "^1.26.0"
|
|
44
47
|
pandas = "^2.3.1"
|
|
48
|
+
polars = "^1.8.2"
|
|
49
|
+
pyarrow = "^16.1.0"
|
|
45
50
|
matplotlib = "^3.10.3"
|
|
51
|
+
plotly = "^5.24.1"
|
|
52
|
+
kaleido = "^0.2.1"
|
|
46
53
|
lxml = "^5.3.0"
|
|
47
54
|
reportlab = "^4.2.5"
|
|
48
55
|
fpdf2 = "^2.7.9"
|
|
56
|
+
wordcloud = "^1.9.3"
|
|
57
|
+
arabic-reshaper = "^3.0.0"
|
|
58
|
+
python-bidi = "^0.4.2"
|
|
59
|
+
nltk = "^3.9.1"
|
|
60
|
+
spacy = "^3.8.4"
|
|
49
61
|
|
|
50
62
|
# ─────────────────────────────────────────────────
|
|
51
63
|
# Optional groups (install with: poetry install --with media,archives,science …)
|
|
@@ -11,6 +11,8 @@ openpyxl>=3.1.2
|
|
|
11
11
|
xlrd>=2.0.1
|
|
12
12
|
python-pptx>=0.6.23
|
|
13
13
|
odfpy>=1.4.1
|
|
14
|
+
pdf2image>=1.16.3
|
|
15
|
+
python-pptx-interface>=0.0.14
|
|
14
16
|
|
|
15
17
|
# -------------------------------------------------------------------
|
|
16
18
|
# MEDIA – images / audio / video
|
|
@@ -35,11 +37,23 @@ rarfile>=4.0
|
|
|
35
37
|
# DATA & SCIENTIFIC
|
|
36
38
|
# -------------------------------------------------------------------
|
|
37
39
|
pandas>=2.2.0
|
|
40
|
+
numpy>=1.26.0
|
|
41
|
+
polars>=1.8.2
|
|
42
|
+
pyarrow>=16.1.0
|
|
38
43
|
tabula-py>=2.8.1
|
|
39
44
|
h5py>=3.10.0
|
|
40
45
|
netCDF4>=1.6.5
|
|
41
46
|
ezdxf>=1.1.1
|
|
42
47
|
seaborn>=0.13.0
|
|
48
|
+
plotly>=5.24.1
|
|
49
|
+
kaleido>=0.2.1
|
|
50
|
+
wordcloud>=1.9.3
|
|
51
|
+
|
|
52
|
+
# -------------------------------------------------------------------
|
|
53
|
+
# NLP & TEXT PROCESSING
|
|
54
|
+
# -------------------------------------------------------------------
|
|
55
|
+
nltk>=3.9.1
|
|
56
|
+
spacy>=3.8.4
|
|
43
57
|
|
|
44
58
|
# -------------------------------------------------------------------
|
|
45
59
|
# ARABIC & RTL TEXT SUPPORT
|
|
@@ -75,7 +75,7 @@ def publish_request_progress(data: Dict[str, Any]) -> bool:
|
|
|
75
75
|
pct_bucket = None
|
|
76
76
|
if not prev or prev.get('info') != info or prev.get('pct_bucket') != pct_bucket:
|
|
77
77
|
_last_logged_progress[rid] = {'info': info, 'pct_bucket': pct_bucket}
|
|
78
|
-
logger.info(f"Published progress update for request {rid}: progress={pct}, subscribers={result}")
|
|
78
|
+
logger.info(f"Published progress update for request {rid}: info='{info}', progress={pct}, subscribers={result}")
|
|
79
79
|
except Exception:
|
|
80
80
|
# Safe fallback if logging diff fails
|
|
81
81
|
logger.debug("Progress publish logged without diff due to exception")
|