unique_toolkit 2026.24.0.dev1__py3-none-any.whl → 2026.24.0.dev3__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.
@@ -161,6 +161,7 @@ Handling User Queries:
161
161
  - Whenever the user query requires using the python tool, you must always think first about the steps required.
162
162
  - CRITICAL: If any step generates a plot or visualization as a PNG, use **matplotlib** — that code block MUST include `plt.savefig('/mnt/data/<filename>.png', bbox_inches='tight')` and `plt.close()` as the final lines. Code that only calls `plt.show()` without saving will NOT display the image to the user.
163
163
  - CRITICAL: NEVER reference a `sandbox:/mnt/data/<filename>` link unless you have already executed code in this response that saved that exact file. Referencing a file that was not created by executed code will result in a broken link.
164
+ - Self-check before writing any sandbox link: look back at the code blocks you executed in this response. Is there a block that explicitly saves this exact filename to `/mnt/data/`? If not, execute the code first — then reference the file.
164
165
  - CRITICAL: The sandbox has NO internet access. NEVER use `requests`, `httpx`, `urllib`, or any other HTTP library to fetch data from the web — these calls will always fail. If the user's query requires live web data (e.g. market prices, news, APIs), you MUST retrieve it using the web search tool first and then pass the result into the code interpreter.
165
166
  - CRITICAL: For Excel files (`.xls`, `.xlsx`) and CSV files uploaded to the chat, ALWAYS use this tool to read and process them (e.g. `pandas.read_excel`, `pandas.read_csv`, `openpyxl`). Do NOT rely on the chat's text content or prior ingestion for spreadsheet data — the raw file contents are only accessible via code execution from `/mnt/data/<filename>`.
166
167
  - For calculation, retrieval, or exploratory-analysis answers, return the result concisely in the chat as markdown (key numbers inline, short tables where useful). Do NOT produce a separate artifact file (HTML, PDF, etc.) unless the user explicitly asked for a downloadable output or the request clearly calls for a dashboard/report.
@@ -620,13 +620,16 @@ class DisplayCodeInterpreterFilesPostProcessor(
620
620
  self._log.info("Fence injection modified the message text")
621
621
 
622
622
  _warn_missing_content_ids(loop_response.message.text or "", self._content_map)
623
+ ci_ran = bool(loop_response.code_interpreter_calls)
623
624
  loop_response.message.text, dangling_replaced = _replace_dangling_sandbox_links(
624
- loop_response.message.text
625
+ loop_response.message.text, ci_ran=ci_ran
625
626
  )
626
627
  changed |= dangling_replaced
627
628
  if dangling_replaced:
628
629
  self._log.warning(
629
- "apply_postprocessing found and replaced dangling sandbox links"
630
+ "apply_postprocessing found and replaced dangling sandbox links "
631
+ "(ci_ran=%s)",
632
+ ci_ran,
630
633
  )
631
634
 
632
635
  apply_ms = (time.monotonic() - apply_t0) * 1000
@@ -1254,7 +1257,9 @@ _SANDBOX_MARKDOWN_LINK_RE = re.compile(r"!?\[.*?\]\(sandbox:/mnt/data/\S+?\)")
1254
1257
  _SANDBOX_FILENAME_RE = re.compile(r"sandbox:/mnt/data/([^)\s]+)")
1255
1258
 
1256
1259
 
1257
- def _replace_dangling_sandbox_links(text: str) -> tuple[str, bool]:
1260
+ def _replace_dangling_sandbox_links(
1261
+ text: str, *, ci_ran: bool = True
1262
+ ) -> tuple[str, bool]:
1258
1263
  """Replace any remaining sandbox:/mnt/data/ markdown links with a per-file notice.
1259
1264
 
1260
1265
  A dangling link means either the LLM hallucinated a file reference (the sandbox
@@ -1263,6 +1268,12 @@ def _replace_dangling_sandbox_links(text: str) -> tuple[str, bool]:
1263
1268
  cases the user would see a broken link; this function replaces each such link with
1264
1269
  an actionable message that names the specific file, and logs a warning so the
1265
1270
  incident is visible in production logs.
1271
+
1272
+ Args:
1273
+ text: The message text to scan for dangling sandbox links.
1274
+ ci_ran: Whether the code interpreter was called at all this turn. When
1275
+ ``False`` the LLM emitted a sandbox link without invoking the tool
1276
+ (hallucination); a more accurate message is shown to the user.
1266
1277
  """
1267
1278
  if not _SANDBOX_MARKDOWN_LINK_RE.search(text):
1268
1279
  return text, False
@@ -1271,11 +1282,17 @@ def _replace_dangling_sandbox_links(text: str) -> tuple[str, bool]:
1271
1282
  filename_match = _SANDBOX_FILENAME_RE.search(m.group())
1272
1283
  filename = filename_match.group(1) if filename_match else "the file"
1273
1284
  logger.warning(
1274
- "Dangling sandbox link found in final text: '%s'. "
1275
- "The file was either never uploaded or the link format did not match "
1285
+ "Dangling sandbox link found in final text: '%s'. ci_ran=%s. "
1286
+ "The file was either never generated or the link format did not match "
1276
1287
  "the expected pattern — replacing with per-file notice.",
1277
1288
  m.group(),
1289
+ ci_ran,
1278
1290
  )
1291
+ if not ci_ran:
1292
+ return (
1293
+ f"⚠️ The file *{filename}* was not generated. "
1294
+ "Please ask me to create it."
1295
+ )
1279
1296
  return f"⚠️ The file *{filename}* could not be retrieved. You can ask me to regenerate it."
1280
1297
 
1281
1298
  return _SANDBOX_MARKDOWN_LINK_RE.sub(_replacement, text), True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: unique-toolkit
3
- Version: 2026.24.0.dev1
3
+ Version: 2026.24.0.dev3
4
4
  Summary:
5
5
  Author: Cedric Klinkert, Martin Fadler, Sadique Sheik, Fabian Schläpfer, Pascal Hauri, Ejiroghene Oki-Peter, Rami Azouz, Ricardo Visini, Sanzio Monti
6
6
  Author-email: Cedric Klinkert <cedric.klinkert@unique.ch>, Martin Fadler <martin.fadler@unique.ch>, Sadique Sheik <sadique@unique.ch>, Fabian Schläpfer <fabian@unique.ch>, Pascal Hauri <pascal@unique.ch>, Ejiroghene Oki-Peter <oki-peter.ejiroghene@unique.ai>, Rami Azouz <rami.ext@unique.ch>, Ricardo Visini <ricardo.visini@unique.ch>, Sanzio Monti <sanzio.monti@unique.ai>
@@ -201,11 +201,11 @@ unique_toolkit/agentic/tools/names.py,sha256=MDF0ONLrxeC-iz--EtyrHAox_RN6zasxo5M
201
201
  unique_toolkit/agentic/tools/openai_builtin/__init__.py,sha256=Q6d9mhsLRVF3erT2yMxLld62D3FTZ8nbovI4vLv4Nso,701
202
202
  unique_toolkit/agentic/tools/openai_builtin/base.py,sha256=Ob5n1S6HduFbI5RsjIklasRjoKsgCwh840KAb6p2IaI,1858
203
203
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py,sha256=PIt8wxfSeNYqExWpvrjZxD5sntd5Wv8bXKfoeCB4XWs,764
204
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py,sha256=QcLbFRbig6H2jh4Eywyho0O9jjbfMEwPFH3K5BcT5uI,19662
204
+ unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py,sha256=9QMjyvxvYmz5oQOt73r__7HmoJdh7yIPQ2wY1Q0F-HM,19906
205
205
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/__init__.py,sha256=ZSNvtRDSRipcfJg9gEsXm9DZDU7ODsAcko9vEmKevmI,584
206
206
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/artifacts.py,sha256=wAgDrcXZbCdDbNWNpbMigBUXySzbKQXSfg3KsZfAWfs,3115
207
207
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/code_display.py,sha256=Q4crOkYG-C_uTSc7rW14cP1H4IWxsKpfuftafDHbjEo,2897
208
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/generated_files.py,sha256=2bcRHoW-FwC8lniGFVIAXwUBK7NoSAmjfqCmJEvATz4,58941
208
+ unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/generated_files.py,sha256=5wkR2GUUisNedkeYJYiS3Tvn-kB6obJmzxgCfo96oEg,59618
209
209
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/schemas.py,sha256=W7egCmYrPrzic0aXsu9wY5fvQ8y_cl4Tzq_cjVs0mZs,542
210
210
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py,sha256=vfu9Z3pNv-jvSz1vP7JzzWzeLrL3l1x5swWMIGRSge4,14160
211
211
  unique_toolkit/agentic/tools/openai_builtin/manager.py,sha256=CkfMRsjrRDv_X-zfJHZnxxOdpCK1qzf6RGGxKtUHp9k,3519
@@ -391,6 +391,6 @@ unique_toolkit/short_term_memory/service.py,sha256=Ncw0_0CNM6kmzJSLVJGG5GcKpBduI
391
391
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
392
392
  unique_toolkit/smart_rules/compile.py,sha256=Ozhh70qCn2yOzRWr9d8WmJeTo7AQurwd3tStgBMPFLA,1246
393
393
  unique_toolkit/test_utilities/events.py,sha256=FLrhMh0A_mQutAUjoD0FdMcVQ4Gq31r35OVGzRjvLro,6760
394
- unique_toolkit-2026.24.0.dev1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
395
- unique_toolkit-2026.24.0.dev1.dist-info/METADATA,sha256=WhTheAC6aGO4P5vZRgzhxcnBr_bu3afhEV_ODkSj2BQ,7392
396
- unique_toolkit-2026.24.0.dev1.dist-info/RECORD,,
394
+ unique_toolkit-2026.24.0.dev3.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
395
+ unique_toolkit-2026.24.0.dev3.dist-info/METADATA,sha256=ZaoaKI5FW8PBEO4jZTDu8Rh1POBUC5M6p1z1px7d6aM,7392
396
+ unique_toolkit-2026.24.0.dev3.dist-info/RECORD,,