@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.
Files changed (91) hide show
  1. package/README.md +1 -0
  2. package/config.js +1 -1
  3. package/helper-apps/cortex-autogen2/.dockerignore +1 -0
  4. package/helper-apps/cortex-autogen2/Dockerfile +6 -10
  5. package/helper-apps/cortex-autogen2/Dockerfile.worker +2 -0
  6. package/helper-apps/cortex-autogen2/agents.py +203 -2
  7. package/helper-apps/cortex-autogen2/main.py +1 -1
  8. package/helper-apps/cortex-autogen2/pyproject.toml +12 -0
  9. package/helper-apps/cortex-autogen2/requirements.txt +14 -0
  10. package/helper-apps/cortex-autogen2/services/redis_publisher.py +1 -1
  11. package/helper-apps/cortex-autogen2/services/run_analyzer.py +1 -1
  12. package/helper-apps/cortex-autogen2/task_processor.py +431 -229
  13. package/helper-apps/cortex-autogen2/test_entity_fetcher.py +305 -0
  14. package/helper-apps/cortex-autogen2/tests/README.md +240 -0
  15. package/helper-apps/cortex-autogen2/tests/TEST_REPORT.md +342 -0
  16. package/helper-apps/cortex-autogen2/tests/__init__.py +8 -0
  17. package/helper-apps/cortex-autogen2/tests/analysis/__init__.py +1 -0
  18. package/helper-apps/cortex-autogen2/tests/analysis/improvement_suggester.py +224 -0
  19. package/helper-apps/cortex-autogen2/tests/analysis/trend_analyzer.py +211 -0
  20. package/helper-apps/cortex-autogen2/tests/cli/__init__.py +1 -0
  21. package/helper-apps/cortex-autogen2/tests/cli/run_tests.py +296 -0
  22. package/helper-apps/cortex-autogen2/tests/collectors/__init__.py +1 -0
  23. package/helper-apps/cortex-autogen2/tests/collectors/log_collector.py +252 -0
  24. package/helper-apps/cortex-autogen2/tests/collectors/progress_collector.py +182 -0
  25. package/helper-apps/cortex-autogen2/tests/conftest.py +15 -0
  26. package/helper-apps/cortex-autogen2/tests/database/__init__.py +1 -0
  27. package/helper-apps/cortex-autogen2/tests/database/repository.py +501 -0
  28. package/helper-apps/cortex-autogen2/tests/database/schema.sql +108 -0
  29. package/helper-apps/cortex-autogen2/tests/evaluators/__init__.py +1 -0
  30. package/helper-apps/cortex-autogen2/tests/evaluators/llm_scorer.py +294 -0
  31. package/helper-apps/cortex-autogen2/tests/evaluators/prompts.py +250 -0
  32. package/helper-apps/cortex-autogen2/tests/evaluators/wordcloud_validator.py +168 -0
  33. package/helper-apps/cortex-autogen2/tests/metrics/__init__.py +1 -0
  34. package/helper-apps/cortex-autogen2/tests/metrics/collector.py +155 -0
  35. package/helper-apps/cortex-autogen2/tests/orchestrator.py +576 -0
  36. package/helper-apps/cortex-autogen2/tests/test_cases.yaml +279 -0
  37. package/helper-apps/cortex-autogen2/tests/test_data.db +0 -0
  38. package/helper-apps/cortex-autogen2/tests/utils/__init__.py +3 -0
  39. package/helper-apps/cortex-autogen2/tests/utils/connectivity.py +112 -0
  40. package/helper-apps/cortex-autogen2/tools/azure_blob_tools.py +74 -24
  41. package/helper-apps/cortex-autogen2/tools/entity_api_registry.json +38 -0
  42. package/helper-apps/cortex-autogen2/tools/file_tools.py +1 -1
  43. package/helper-apps/cortex-autogen2/tools/search_tools.py +436 -238
  44. package/helper-apps/cortex-file-handler/package-lock.json +2 -2
  45. package/helper-apps/cortex-file-handler/package.json +1 -1
  46. package/helper-apps/cortex-file-handler/scripts/setup-test-containers.js +4 -5
  47. package/helper-apps/cortex-file-handler/src/blobHandler.js +36 -144
  48. package/helper-apps/cortex-file-handler/src/services/FileConversionService.js +5 -3
  49. package/helper-apps/cortex-file-handler/src/services/storage/AzureStorageProvider.js +34 -1
  50. package/helper-apps/cortex-file-handler/src/services/storage/GCSStorageProvider.js +22 -0
  51. package/helper-apps/cortex-file-handler/src/services/storage/LocalStorageProvider.js +28 -1
  52. package/helper-apps/cortex-file-handler/src/services/storage/StorageFactory.js +29 -4
  53. package/helper-apps/cortex-file-handler/src/services/storage/StorageProvider.js +11 -0
  54. package/helper-apps/cortex-file-handler/src/services/storage/StorageService.js +1 -1
  55. package/helper-apps/cortex-file-handler/tests/blobHandler.test.js +3 -2
  56. package/helper-apps/cortex-file-handler/tests/checkHashShortLived.test.js +8 -1
  57. package/helper-apps/cortex-file-handler/tests/containerConversionFlow.test.js +5 -2
  58. package/helper-apps/cortex-file-handler/tests/containerNameParsing.test.js +14 -7
  59. package/helper-apps/cortex-file-handler/tests/containerParameterFlow.test.js +5 -2
  60. package/helper-apps/cortex-file-handler/tests/storage/StorageFactory.test.js +31 -19
  61. package/lib/entityConstants.js +3 -0
  62. package/package.json +2 -2
  63. package/pathways/system/entity/sys_entity_agent.js +2 -1
  64. package/pathways/system/entity/tools/sys_tool_codingagent.js +2 -2
  65. package/pathways/system/workspaces/workspace_applet_edit.js +551 -29
  66. package/server/modelExecutor.js +4 -0
  67. package/server/plugins/claude4VertexPlugin.js +540 -0
  68. package/server/plugins/openAiWhisperPlugin.js +43 -2
  69. package/tests/integration/rest/vendors/claude_streaming.test.js +121 -0
  70. package/tests/unit/plugins/claude4VertexPlugin.test.js +462 -0
  71. package/tests/unit/plugins/claude4VertexToolConversion.test.js +413 -0
  72. package/helper-apps/cortex-autogen/.funcignore +0 -8
  73. package/helper-apps/cortex-autogen/Dockerfile +0 -10
  74. package/helper-apps/cortex-autogen/OAI_CONFIG_LIST +0 -6
  75. package/helper-apps/cortex-autogen/agents.py +0 -493
  76. package/helper-apps/cortex-autogen/agents_extra.py +0 -14
  77. package/helper-apps/cortex-autogen/config.py +0 -18
  78. package/helper-apps/cortex-autogen/data_operations.py +0 -29
  79. package/helper-apps/cortex-autogen/function_app.py +0 -44
  80. package/helper-apps/cortex-autogen/host.json +0 -15
  81. package/helper-apps/cortex-autogen/main.py +0 -38
  82. package/helper-apps/cortex-autogen/prompts.py +0 -196
  83. package/helper-apps/cortex-autogen/prompts_extra.py +0 -5
  84. package/helper-apps/cortex-autogen/requirements.txt +0 -9
  85. package/helper-apps/cortex-autogen/search.py +0 -85
  86. package/helper-apps/cortex-autogen/test.sh +0 -40
  87. package/helper-apps/cortex-autogen/tools/sasfileuploader.py +0 -66
  88. package/helper-apps/cortex-autogen/utils.py +0 -88
  89. package/helper-apps/cortex-autogen2/DigiCertGlobalRootCA.crt.pem +0 -22
  90. package/helper-apps/cortex-autogen2/poetry.lock +0 -3652
  91. 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
@@ -528,7 +528,7 @@ var config = convict({
528
528
  "supportsStreaming": true
529
529
  },
530
530
  "claude-4-sonnet-vertex": {
531
- "type": "CLAUDE-3-VERTEX",
531
+ "type": "CLAUDE-4-VERTEX",
532
532
  "url": "{{claudeVertexUrl}}",
533
533
  "headers": {
534
534
  "Content-Type": "application/json"
@@ -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-liberation2 \
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-serial-dev hdf5-tools \
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,8 @@ WORKDIR /app
8
8
  RUN apt-get update && apt-get install -y \
9
9
  gcc \
10
10
  curl \
11
+ libreoffice-core libreoffice-writer libreoffice-impress \
12
+ poppler-utils \
11
13
  && rm -rf /var/lib/apt/lists/*
12
14
 
13
15
  # Install poetry
@@ -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(upload_file_to_azure_blob, description="Upload files to the cloud. You must use absolute path to reference local files.")
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.warning(f"⚠️ Failed to decode as base64, trying as raw JSON: {e}")
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")
@@ -426,7 +426,7 @@ def build_run_document(
426
426
  doc = {
427
427
  "id": task_id,
428
428
  "date": now_iso,
429
- "task": _truncate(redact(task_text), 4000),
429
+ "task": redact(task_text),
430
430
  "content": content_blob,
431
431
  "requestId": task_id,
432
432
  }