unique_orchestrator 2026.38.0.dev2__tar.gz → 2026.38.0.dev4__tar.gz

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 (34) hide show
  1. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/PKG-INFO +4 -4
  2. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/pyproject.toml +4 -4
  3. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/config.py +24 -15
  4. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_config_services_validators.py +8 -2
  5. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_register_code_interpreter_postprocessors.py +7 -28
  6. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/unique_ai_builder.py +4 -4
  7. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/README.md +0 -0
  8. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/__init__.py +0 -0
  9. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/_builders/__init__.py +0 -0
  10. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/_builders/history_manager.py +0 -0
  11. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/_builders/inject_tool_reminders.py +0 -0
  12. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/_builders/loop_iteration_runner.py +0 -0
  13. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/_builders/open_file_setup.py +0 -0
  14. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/_builders/skill_setup.py +0 -0
  15. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/prompts/generic_reference_prompt.jinja2 +0 -0
  16. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/prompts/system_prompt.jinja2 +0 -0
  17. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/prompts/user_message_prompt.jinja2 +0 -0
  18. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/settings.py +0 -0
  19. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_agent_config_rjsf_ui_schema.py +0 -0
  20. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_build_loop_iteration_runner.py +0 -0
  21. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_qwen_max_loop_iterations.py +0 -0
  22. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_async_modify.py +0 -0
  23. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_execution_timing.py +0 -0
  24. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_get_filtered_user_metadata.py +0 -0
  25. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_log_tool_calls.py +0 -0
  26. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_loop_debug_params.py +0 -0
  27. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_persist_tool_calls.py +0 -0
  28. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_plan_or_execute_include.py +0 -0
  29. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_reference_order.py +0 -0
  30. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_render_system_prompt_user_instructions.py +0 -0
  31. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_unique_ai_token_usage.py +0 -0
  32. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/tests/test_utils_resolve_other_options.py +0 -0
  33. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/unique_ai.py +0 -0
  34. {unique_orchestrator-2026.38.0.dev2 → unique_orchestrator-2026.38.0.dev4}/unique_orchestrator/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: unique-orchestrator
3
- Version: 2026.38.0.dev2
3
+ Version: 2026.38.0.dev4
4
4
  Summary:
5
5
  Author: Andreas Hauri
6
6
  Author-email: Andreas Hauri <andreas.hauri@unique.ai>
@@ -9,15 +9,15 @@ Requires-Dist: pydantic>=2.8.2,<3
9
9
  Requires-Dist: pydantic-settings>=2.10.1,<3
10
10
  Requires-Dist: typing-extensions>=4.9.0,<5
11
11
  Requires-Dist: jinja2>=3.1.0,<4
12
- Requires-Dist: unique-toolkit>=2026.38.0.dev8,<2026.38.0rc0
12
+ Requires-Dist: unique-toolkit>=2026.38.0.dev15,<2026.38.0rc0
13
13
  Requires-Dist: unique-stock-ticker>=2026.38.0.dev1,<2026.38.0rc0
14
14
  Requires-Dist: unique-follow-up-questions>=2026.38.0.dev1,<2026.38.0rc0
15
15
  Requires-Dist: unique-internal-search>=2026.38.0.dev1,<2026.38.0rc0
16
16
  Requires-Dist: unique-deep-research>=2026.38.0.dev1,<2026.38.0rc0
17
- Requires-Dist: unique-web-search>=2026.38.0.dev1,<2026.38.0rc0
17
+ Requires-Dist: unique-web-search>=2026.38.0.dev2,<2026.38.0rc0
18
18
  Requires-Dist: unique-swot>=2026.38.0.dev1,<2026.38.0rc0
19
19
  Requires-Dist: unique-skill-tool>=2026.38.0.dev1,<2026.38.0rc0
20
- Requires-Dist: unique-user-memory>=2026.38.0.dev1,<2026.38.0rc0
20
+ Requires-Dist: unique-user-memory>=2026.38.0.dev3,<2026.38.0rc0
21
21
  Requires-Dist: openai>=1.109.1,<3
22
22
  Requires-Python: >=3.12, <4
23
23
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "unique_orchestrator"
3
- version = "2026.38.0.dev2"
3
+ version = "2026.38.0.dev4"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  license = { text = "Proprietary" }
@@ -13,15 +13,15 @@ dependencies = [
13
13
  "pydantic-settings>=2.10.1,<3",
14
14
  "typing-extensions>=4.9.0,<5",
15
15
  "jinja2>=3.1.0,<4",
16
- "unique-toolkit>=2026.38.0.dev8,<2026.38.0rc0",
16
+ "unique-toolkit>=2026.38.0.dev15,<2026.38.0rc0",
17
17
  "unique-stock-ticker>=2026.38.0.dev1,<2026.38.0rc0",
18
18
  "unique-follow-up-questions>=2026.38.0.dev1,<2026.38.0rc0",
19
19
  "unique-internal-search>=2026.38.0.dev1,<2026.38.0rc0",
20
20
  "unique-deep-research>=2026.38.0.dev1,<2026.38.0rc0",
21
- "unique-web-search>=2026.38.0.dev1,<2026.38.0rc0",
21
+ "unique-web-search>=2026.38.0.dev2,<2026.38.0rc0",
22
22
  "unique-swot>=2026.38.0.dev1,<2026.38.0rc0",
23
23
  "unique-skill-tool>=2026.38.0.dev1,<2026.38.0rc0",
24
- "unique-user-memory>=2026.38.0.dev1,<2026.38.0rc0",
24
+ "unique-user-memory>=2026.38.0.dev3,<2026.38.0rc0",
25
25
  "openai>=1.109.1,<3",
26
26
  ]
27
27
 
@@ -518,6 +518,26 @@ class UniqueAIAgentConfig(BaseToolConfig):
518
518
  experimental: ExperimentalConfig = ExperimentalConfig()
519
519
 
520
520
 
521
+ # GPT frontier models (GPT-5.5 and newer) that must be served via the Responses API.
522
+ # TEMP FIX, see `UniqueAIConfig.enable_responses_api_for_gpt_frontier_models`.
523
+ GPT_FRONTIER_MODELS: frozenset[LanguageModelName] = frozenset(
524
+ {
525
+ LanguageModelName.AZURE_GPT_55_2026_0424,
526
+ LanguageModelName.AZURE_GPT_55_PRO_2026_0424,
527
+ LanguageModelName.AZURE_GPT_56_SOL_2026_0709,
528
+ LanguageModelName.AZURE_GPT_56_TERRA_2026_0709,
529
+ LanguageModelName.AZURE_GPT_56_LUNA_2026_0709,
530
+ LanguageModelName.AZURE_GPT_6_ASTRA_2026_0903,
531
+ LanguageModelName.LITELLM_OPENAI_GPT_55,
532
+ LanguageModelName.LITELLM_OPENAI_GPT_55_PRO,
533
+ LanguageModelName.LITELLM_OPENAI_GPT_56_SOL,
534
+ LanguageModelName.LITELLM_OPENAI_GPT_56_TERRA,
535
+ LanguageModelName.LITELLM_OPENAI_GPT_56_LUNA,
536
+ LanguageModelName.LITELLM_OPENAI_GPT_6_ASTRA,
537
+ }
538
+ )
539
+
540
+
521
541
  class UniqueAIConfig(BaseToolConfig):
522
542
  space: UniqueAISpaceConfig = UniqueAISpaceConfig()
523
543
 
@@ -579,27 +599,16 @@ class UniqueAIConfig(BaseToolConfig):
579
599
  return self
580
600
 
581
601
  @model_validator(mode="after")
582
- def enable_responses_api_for_gpt_55_and_gpt_56_models(self) -> "UniqueAIConfig":
583
- """Auto-enable the Responses API for GPT-5.5 and GPT-5.6 models.
602
+ def enable_responses_api_for_gpt_frontier_models(self) -> "UniqueAIConfig":
603
+ """Auto-enable the Responses API for GPT frontier models (GPT-5.5 and newer).
584
604
 
585
- TEMP FIX: GPT-5.5 and GPT-5.6 reject requests that combine `tools` with
605
+ TEMP FIX: these models reject requests that combine `tools` with
586
606
  `reasoning_effort` on /v1/chat/completions and demand /v1/responses.
587
607
  Forcing the Responses API here avoids the OpenAI 400 error until the
588
608
  runner can pick the right transport based on model capabilities.
589
609
  Tracked in Jira: UN-20123.
590
610
  """
591
- if self.space.language_model.name in {
592
- LanguageModelName.AZURE_GPT_55_2026_0424,
593
- LanguageModelName.AZURE_GPT_55_PRO_2026_0424,
594
- LanguageModelName.AZURE_GPT_56_SOL_2026_0709,
595
- LanguageModelName.AZURE_GPT_56_TERRA_2026_0709,
596
- LanguageModelName.AZURE_GPT_56_LUNA_2026_0709,
597
- LanguageModelName.LITELLM_OPENAI_GPT_55,
598
- LanguageModelName.LITELLM_OPENAI_GPT_55_PRO,
599
- LanguageModelName.LITELLM_OPENAI_GPT_56_SOL,
600
- LanguageModelName.LITELLM_OPENAI_GPT_56_TERRA,
601
- LanguageModelName.LITELLM_OPENAI_GPT_56_LUNA,
602
- }:
611
+ if self.space.language_model.name in GPT_FRONTIER_MODELS:
603
612
  self.agent.experimental.responses_api_config.use_responses_api = True
604
613
  return self
605
614
 
@@ -293,8 +293,8 @@ class TestUniqueAIConfigOpenFileValidator:
293
293
  assert config.agent.experimental.responses_api_config.use_responses_api is True
294
294
 
295
295
 
296
- class TestUniqueAIConfigGpt55AndGpt56ResponsesApiValidator:
297
- """Tests for the GPT-5.5 and GPT-5.6 Responses API validator.
296
+ class TestUniqueAIConfigGptFrontierModelsResponsesApiValidator:
297
+ """Tests for the GPT frontier models (GPT-5.5 and newer) Responses API validator.
298
298
 
299
299
  These models reject requests that combine `tools` with `reasoning_effort`
300
300
  on /v1/chat/completions and demand /v1/responses. The validator forces the
@@ -310,11 +310,13 @@ class TestUniqueAIConfigGpt55AndGpt56ResponsesApiValidator:
310
310
  LanguageModelName.AZURE_GPT_56_SOL_2026_0709,
311
311
  LanguageModelName.AZURE_GPT_56_TERRA_2026_0709,
312
312
  LanguageModelName.AZURE_GPT_56_LUNA_2026_0709,
313
+ LanguageModelName.AZURE_GPT_6_ASTRA_2026_0903,
313
314
  LanguageModelName.LITELLM_OPENAI_GPT_55,
314
315
  LanguageModelName.LITELLM_OPENAI_GPT_55_PRO,
315
316
  LanguageModelName.LITELLM_OPENAI_GPT_56_SOL,
316
317
  LanguageModelName.LITELLM_OPENAI_GPT_56_TERRA,
317
318
  LanguageModelName.LITELLM_OPENAI_GPT_56_LUNA,
319
+ LanguageModelName.LITELLM_OPENAI_GPT_6_ASTRA,
318
320
  ],
319
321
  )
320
322
  def test_enables_responses_api_for_affected_models(
@@ -337,11 +339,13 @@ class TestUniqueAIConfigGpt55AndGpt56ResponsesApiValidator:
337
339
  LanguageModelName.AZURE_GPT_56_SOL_2026_0709,
338
340
  LanguageModelName.AZURE_GPT_56_TERRA_2026_0709,
339
341
  LanguageModelName.AZURE_GPT_56_LUNA_2026_0709,
342
+ LanguageModelName.AZURE_GPT_6_ASTRA_2026_0903,
340
343
  LanguageModelName.LITELLM_OPENAI_GPT_55,
341
344
  LanguageModelName.LITELLM_OPENAI_GPT_55_PRO,
342
345
  LanguageModelName.LITELLM_OPENAI_GPT_56_SOL,
343
346
  LanguageModelName.LITELLM_OPENAI_GPT_56_TERRA,
344
347
  LanguageModelName.LITELLM_OPENAI_GPT_56_LUNA,
348
+ LanguageModelName.LITELLM_OPENAI_GPT_6_ASTRA,
345
349
  ],
346
350
  )
347
351
  def test_enables_responses_api_for_affected_models_with_tools(
@@ -373,11 +377,13 @@ class TestUniqueAIConfigGpt55AndGpt56ResponsesApiValidator:
373
377
  LanguageModelName.AZURE_GPT_56_SOL_2026_0709,
374
378
  LanguageModelName.AZURE_GPT_56_TERRA_2026_0709,
375
379
  LanguageModelName.AZURE_GPT_56_LUNA_2026_0709,
380
+ LanguageModelName.AZURE_GPT_6_ASTRA_2026_0903,
376
381
  LanguageModelName.LITELLM_OPENAI_GPT_55,
377
382
  LanguageModelName.LITELLM_OPENAI_GPT_55_PRO,
378
383
  LanguageModelName.LITELLM_OPENAI_GPT_56_SOL,
379
384
  LanguageModelName.LITELLM_OPENAI_GPT_56_TERRA,
380
385
  LanguageModelName.LITELLM_OPENAI_GPT_56_LUNA,
386
+ LanguageModelName.LITELLM_OPENAI_GPT_6_ASTRA,
381
387
  ],
382
388
  )
383
389
  def test_keeps_responses_api_enabled_when_already_enabled(
@@ -194,7 +194,7 @@ class TestConfigPassthrough:
194
194
  )
195
195
 
196
196
  custom_code_display_config = ShowExecutedCodePostprocessorConfig(
197
- sleep_time_before_display=1.5
197
+ remove_from_history=False
198
198
  )
199
199
  ci_config = CodeInterpreterExtendedConfig(
200
200
  executed_code_display_config=custom_code_display_config
@@ -217,27 +217,6 @@ class TestConfigPassthrough:
217
217
  )
218
218
  assert postprocessor._config is custom_code_display_config
219
219
 
220
- @pytest.mark.ai
221
- def test_show_executed_code_postprocessor_receives_company_id(self):
222
- """ShowExecutedCodePostprocessor must receive company_id for fence FF checks (UN-17972)."""
223
- mgr = _make_postprocessor_manager()
224
-
225
- _register_code_interpreter_postprocessors(
226
- tools=[_make_code_interpreter_tool()],
227
- postprocessor_manager=mgr,
228
- client=MagicMock(),
229
- content_service=MagicMock(),
230
- user_id="u1",
231
- company_id="company-fence",
232
- chat_id="ch1",
233
- chat_service=MagicMock(),
234
- )
235
-
236
- postprocessor: ShowExecutedCodePostprocessor = (
237
- mgr.add_postprocessor.call_args_list[0][0][0]
238
- )
239
- assert postprocessor._company_id == "company-fence"
240
-
241
220
  @pytest.mark.ai
242
221
  def test_display_files_postprocessor_receives_client_and_company_id(self):
243
222
  """DisplayCodeInterpreterFilesPostProcessor must receive the client and company_id."""
@@ -281,12 +260,12 @@ class TestFirstMatchWins:
281
260
 
282
261
  first_config = CodeInterpreterExtendedConfig(
283
262
  executed_code_display_config=ShowExecutedCodePostprocessorConfig(
284
- sleep_time_before_display=0.1
263
+ remove_from_history=False
285
264
  )
286
265
  )
287
266
  second_config = CodeInterpreterExtendedConfig(
288
267
  executed_code_display_config=ShowExecutedCodePostprocessorConfig(
289
- sleep_time_before_display=9.9
268
+ remove_from_history=True
290
269
  )
291
270
  )
292
271
  mgr = _make_postprocessor_manager()
@@ -308,7 +287,7 @@ class TestFirstMatchWins:
308
287
  postprocessor: ShowExecutedCodePostprocessor = (
309
288
  mgr.add_postprocessor.call_args_list[0][0][0]
310
289
  )
311
- assert postprocessor._config.sleep_time_before_display == 0.1
290
+ assert postprocessor._config is first_config.executed_code_display_config
312
291
 
313
292
  @pytest.mark.ai
314
293
  def test_skips_disabled_tool_and_uses_next_enabled_code_interpreter(self):
@@ -319,12 +298,12 @@ class TestFirstMatchWins:
319
298
 
320
299
  disabled_config = CodeInterpreterExtendedConfig(
321
300
  executed_code_display_config=ShowExecutedCodePostprocessorConfig(
322
- sleep_time_before_display=9.9
301
+ remove_from_history=True
323
302
  )
324
303
  )
325
304
  enabled_config = CodeInterpreterExtendedConfig(
326
305
  executed_code_display_config=ShowExecutedCodePostprocessorConfig(
327
- sleep_time_before_display=0.5
306
+ remove_from_history=False
328
307
  )
329
308
  )
330
309
  mgr = _make_postprocessor_manager()
@@ -346,4 +325,4 @@ class TestFirstMatchWins:
346
325
  postprocessor: ShowExecutedCodePostprocessor = (
347
326
  mgr.add_postprocessor.call_args_list[0][0][0]
348
327
  )
349
- assert postprocessor._config.sleep_time_before_display == 0.5
328
+ assert postprocessor._config is enabled_config.executed_code_display_config
@@ -489,9 +489,10 @@ def _register_code_interpreter_postprocessors(
489
489
  ) -> None:
490
490
  """Find the first enabled Code Interpreter tool and register its postprocessors.
491
491
 
492
- When a CODE_INTERPRETER tool is present and enabled, both the executed-code
493
- display postprocessor and the generated-files postprocessor are unconditionally
494
- registered so that all Code Interpreter output is surfaced to the user.
492
+ When a CODE_INTERPRETER tool is present and enabled, both the generated-files
493
+ postprocessor (which turns produced files into codeExecution fences) and the
494
+ legacy code-display postprocessor (which only strips old `<details>` blocks
495
+ from the history) are registered.
495
496
  """
496
497
  code_interpreter_config = None
497
498
  for tool in tools:
@@ -507,7 +508,6 @@ def _register_code_interpreter_postprocessors(
507
508
  postprocessor_manager.add_postprocessor(
508
509
  ShowExecutedCodePostprocessor(
509
510
  config=code_interpreter_config.executed_code_display_config,
510
- company_id=company_id,
511
511
  )
512
512
  )
513
513
  postprocessor_manager.add_postprocessor(