agentx-python 0.8.16__tar.gz → 0.8.18__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 (96) hide show
  1. {agentx_python-0.8.16/agentx_python.egg-info → agentx_python-0.8.18}/PKG-INFO +1 -1
  2. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/datasets.py +1 -1
  3. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/evaluation_settings.py +1 -1
  4. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/models.py +2 -2
  5. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/runner.py +5 -8
  6. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/client.py +30 -5
  7. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/patterns.py +4 -0
  8. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/scorer_groups.py +4 -2
  9. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/sessions.py +13 -0
  10. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/version.py +2 -2
  11. {agentx_python-0.8.16 → agentx_python-0.8.18/agentx_python.egg-info}/PKG-INFO +1 -1
  12. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_integrations.py +3 -1
  13. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_selfhost_analysis_fallback.py +8 -2
  14. {agentx_python-0.8.16 → agentx_python-0.8.18}/LICENSE +0 -0
  15. {agentx_python-0.8.16 → agentx_python-0.8.18}/README.md +0 -0
  16. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/__init__.py +0 -0
  17. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/agentx.py +0 -0
  18. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/cli.py +0 -0
  19. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/__init__.py +0 -0
  20. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/_term.py +0 -0
  21. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/adapters/__init__.py +0 -0
  22. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/adapters/http_endpoint.py +0 -0
  23. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/adapters/precomputed.py +0 -0
  24. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/adapters/raw.py +0 -0
  25. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/client.py +0 -0
  26. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/prompts.py +0 -0
  27. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/reporting.py +0 -0
  28. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/results.py +0 -0
  29. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/tool_schemas.py +0 -0
  30. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/evaluations/tracing.py +0 -0
  31. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/exceptions.py +0 -0
  32. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/export.py +0 -0
  33. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/feedback.py +0 -0
  34. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/__init__.py +0 -0
  35. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/_traced_call.py +0 -0
  36. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/anthropic.py +0 -0
  37. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/autogen.py +0 -0
  38. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/crewai.py +0 -0
  39. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/databricks.py +0 -0
  40. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/google_adk.py +0 -0
  41. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/google_genai.py +0 -0
  42. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/langchain.py +0 -0
  43. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/litellm.py +0 -0
  44. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/llamaindex.py +0 -0
  45. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/moveworks.py +0 -0
  46. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/openai.py +0 -0
  47. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/integrations/openai_agents.py +0 -0
  48. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/__init__.py +0 -0
  49. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/agents.py +0 -0
  50. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/improvement_groups.py +0 -0
  51. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/judge_scorers.py +0 -0
  52. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/models.py +0 -0
  53. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/online_evaluators.py +0 -0
  54. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/profile.py +0 -0
  55. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/review_queue.py +0 -0
  56. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/rules.py +0 -0
  57. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/scorers.py +0 -0
  58. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/monitor/signals.py +0 -0
  59. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/outcomes.py +0 -0
  60. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/projects.py +0 -0
  61. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/py.typed +0 -0
  62. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/resources/__init__.py +0 -0
  63. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/resources/agent.py +0 -0
  64. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/resources/conversation.py +0 -0
  65. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/resources/workforce.py +0 -0
  66. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/testing.py +0 -0
  67. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/traces.py +0 -0
  68. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/tracing/__init__.py +0 -0
  69. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/tracing/ci_types.py +0 -0
  70. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/tracing/eval_scope.py +0 -0
  71. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/tracing/framework_detect.py +0 -0
  72. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/tracing/ingest_client.py +0 -0
  73. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/tracing/tracer.py +0 -0
  74. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx/util.py +0 -0
  75. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx_python.egg-info/SOURCES.txt +0 -0
  76. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx_python.egg-info/dependency_links.txt +0 -0
  77. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx_python.egg-info/entry_points.txt +0 -0
  78. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx_python.egg-info/not-zip-safe +0 -0
  79. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx_python.egg-info/requires.txt +0 -0
  80. {agentx_python-0.8.16 → agentx_python-0.8.18}/agentx_python.egg-info/top_level.txt +0 -0
  81. {agentx_python-0.8.16 → agentx_python-0.8.18}/setup.cfg +0 -0
  82. {agentx_python-0.8.16 → agentx_python-0.8.18}/setup.py +0 -0
  83. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_cli_launcher.py +0 -0
  84. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_deep_dive_fixes.py +0 -0
  85. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_docs_match_sdk.py +0 -0
  86. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_eval_scope.py +0 -0
  87. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_framework_detect.py +0 -0
  88. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_integration.py +0 -0
  89. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_judge_scorers.py +0 -0
  90. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_multi_judge.py +0 -0
  91. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_pairwise.py +0 -0
  92. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_review_queue.py +0 -0
  93. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_runner_features.py +0 -0
  94. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_selfhost_compat.py +0 -0
  95. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_span_tree.py +0 -0
  96. {agentx_python-0.8.16 → agentx_python-0.8.18}/tests/test_testing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-python
3
- Version: 0.8.16
3
+ Version: 0.8.18
4
4
  Summary: Official Python SDK for AgentX (https://www.agentx.so/)
5
5
  Home-page: https://github.com/AgentX-ai/AgentX-python
6
6
  Author: Robin Wang and AgentX Team
@@ -48,7 +48,7 @@ class DatasetBuilder:
48
48
  "questions": [],
49
49
  }
50
50
  # LLM-as-judge overrides for this dataset's own grading config. Omit either to keep the
51
- # server default (raw prompt template / OpenAI gpt-5.5, see EVALUATIONS.md). judge_model
51
+ # server default (raw prompt template / gpt-5.6-luna, see EVALUATIONS.md). judge_model
52
52
  # must be one of client.evaluations.list_models() (OpenAI or Anthropic).
53
53
  if judge_prompt is not None:
54
54
  self._payload["judgePrompt"] = judge_prompt
@@ -45,7 +45,7 @@ class EvaluationSettingsBuilder:
45
45
  "evaluationCriteria": evaluation_criteria,
46
46
  }
47
47
  # LLM-as-judge overrides. Omit either to keep the server default (raw prompt template /
48
- # OpenAI gpt-5.5, see EVALUATIONS.md). judge_model must be one of
48
+ # gpt-5.6-luna, see EVALUATIONS.md). judge_model must be one of
49
49
  # client.evaluations.list_models() (OpenAI or Anthropic).
50
50
  if judge_prompt is not None:
51
51
  self._payload["judgePrompt"] = judge_prompt
@@ -113,8 +113,8 @@ class EvaluationSettings(BaseModel):
113
113
  evaluation_criteria: Optional[str] = Field(default=None, alias="evaluationCriteria")
114
114
  # Custom code scorers on this scorer's offline profile - [{ id, name, code, enabled }].
115
115
  code_scorers: Optional[List[Dict[str, Any]]] = Field(default=None, alias="codeScorers")
116
- # LLM-as-judge overrides. None means "use the server default" (raw prompt template / OpenAI
117
- # gpt-5.5). See client.evaluations.settings.builder(judge_prompt=..., judge_model=...).
116
+ # LLM-as-judge overrides. None means "use the server default" (raw prompt template /
117
+ # gpt-5.6-luna). See client.evaluations.settings.builder(judge_prompt=..., judge_model=...).
118
118
  judge_prompt: Optional[str] = Field(default=None, alias="judgePrompt")
119
119
  judge_model: Optional[str] = Field(default=None, alias="judgeModel")
120
120
  status: str = "published"
@@ -63,9 +63,6 @@ _ANALYSIS_LEVEL_LABELS = {
63
63
  "l4_final_reduce": "writing final report",
64
64
  }
65
65
 
66
- _DEFAULT_JUDGE_MODEL = "gpt-5.5"
67
-
68
-
69
66
  class GateResult:
70
67
  """Wire result of the CI gate (GET /runs/:id/gate) with attribute access for the fields a
71
68
  CI script actually branches on."""
@@ -456,16 +453,16 @@ class EvaluationRunContext:
456
453
  Args:
457
454
  mode: "auto" (default), "sync", or "batch" - how item scoring executes server-side.
458
455
  quality_mode: "quality_first" or "balanced" - how many items get a second/third judge.
459
- judges: 1-3 model ids, e.g. ``["gpt-5.5", "claude-opus-4-8"]``. Defaults to a single
460
- judge, ``["gpt-5.5"]``, rather than the dashboard's 3-judge default - SDK runs are
461
- typically lighter-weight, quick-start evaluations.
456
+ judges: 1-3 model ids from ``client.evaluations.list_models()``, e.g.
457
+ ``["gpt-5.6-luna", "claude-opus-4-8"]``. Omit to let the engine score with its
458
+ platform default model (a single judge, rather than the dashboard's 3-judge
459
+ default - SDK runs are typically lighter-weight, quick-start evaluations).
462
460
  poll_interval: seconds between status checks while waiting.
463
461
  timeout: give up waiting after this many seconds (the job keeps running server-side;
464
462
  call ``get_report()`` later to check on it).
465
463
  """
466
464
  if judges is not None and not (1 <= len(judges) <= 3):
467
465
  raise ValueError("judges must contain 1-3 model ids")
468
- resolved_judges = judges if judges is not None else [_DEFAULT_JUDGE_MODEL]
469
466
 
470
467
  _say()
471
468
  with Spinner("Analyzing - AI is reviewing your results") as spinner:
@@ -474,7 +471,7 @@ class EvaluationRunContext:
474
471
  self._run.run_id,
475
472
  mode=mode,
476
473
  quality_mode=quality_mode,
477
- judges=resolved_judges,
474
+ judges=judges,
478
475
  )
479
476
  deadline = time.monotonic() + timeout
480
477
  status = self._client.get_analysis_status(self._run.run_id)
@@ -187,10 +187,17 @@ class MonitorClient:
187
187
  return self._base_url[: -len(suffix)]
188
188
  return self._base_url
189
189
 
190
- def _request(self, method: str, path: str, timeout: int = 30, base: Optional[str] = None, **kwargs) -> Any:
190
+ def _request(
191
+ self, method: str, path: str, timeout: int = 30, base: Optional[str] = None, retry: bool = True, **kwargs
192
+ ) -> Any:
193
+ # retry=False for non-idempotent judge-spending POSTs (sweep, coherence, portability,
194
+ # tuning): a client-side timeout must not fire the same LLM-billing work a second time
195
+ # while the first invocation is still running server-side. Same precedent as
196
+ # EvaluationsClient._request / analyze_run.
191
197
  url = f"{base or self._base_url}{path}"
192
198
  last_exc: Optional[Exception] = None
193
- for attempt, wait in enumerate([0.0] + _RETRY_BACKOFF):
199
+ schedule = [0.0] + _RETRY_BACKOFF if retry else [0.0]
200
+ for attempt, wait in enumerate(schedule):
194
201
  if wait:
195
202
  time.sleep(wait)
196
203
  try:
@@ -204,7 +211,7 @@ class MonitorClient:
204
211
  raise AgentXAuthError("Invalid or missing API key")
205
212
  if resp.status_code == 422:
206
213
  raise AgentXValidationError(resp.text)
207
- if resp.status_code in _RETRYABLE_STATUS and attempt < _MAX_RETRIES - 1:
214
+ if retry and resp.status_code in _RETRYABLE_STATUS and attempt < _MAX_RETRIES - 1:
208
215
  logger.debug(
209
216
  "Retryable status %d (attempt %d)", resp.status_code, attempt + 1
210
217
  )
@@ -421,7 +428,7 @@ class MonitorClient:
421
428
  button. Raises AgentXMonitorError if the engine has no judge key configured."""
422
429
  data = self._request(
423
430
  "POST", f"/agent-monitoring/sessions/{session_id}/coherence-check",
424
- base=self._api_root(), timeout=180,
431
+ base=self._api_root(), timeout=180, retry=False,
425
432
  )
426
433
  return data.get("score", data) if isinstance(data, dict) else data
427
434
 
@@ -429,6 +436,24 @@ class MonitorClient:
429
436
  data = self._request("GET", f"/ingest/sessions/{session_id}/spans", base=self._api_root())
430
437
  return data.get("spans", []) if isinstance(data, dict) else data
431
438
 
439
+ def list_session_scores(self, session_id: str) -> List[dict]:
440
+ """Every session-level verdict on the session, newest first: session-scoped online
441
+ evaluators (kind ``online-eval:<id>``), session-scoped scorer groups
442
+ (``scorer-group:<id>``), and legacy coherence rows."""
443
+ data = self._request(
444
+ "GET", f"/agent-monitoring/sessions/{session_id}/scores", base=self._api_root()
445
+ )
446
+ return data.get("scores", []) if isinstance(data, dict) else data
447
+
448
+ def run_session_sweep(self) -> dict:
449
+ """Run the idle-session sweep once, now - the tick that scores quiet multi-turn
450
+ sessions with every enabled session-scoped evaluator and scorer group. Production
451
+ engines run this automatically every minute; the manual trigger exists for demos,
452
+ tests, and backfills. Returns ``{"judged": n}``."""
453
+ return self._request(
454
+ "POST", "/agent-monitoring/session-sweep/run", base=self._api_root(), timeout=300, retry=False
455
+ )
456
+
432
457
  # ------------------------------------------------------------------
433
458
  # Model portability (self-host): replay a trace's input against other models
434
459
  # ------------------------------------------------------------------
@@ -439,7 +464,7 @@ class MonitorClient:
439
464
  plus judging, so expect tens of seconds."""
440
465
  return self._request(
441
466
  "POST", f"/agent-monitoring/traces/{trace_id}/portability",
442
- base=self._api_root(), json={"modelIds": model_ids}, timeout=300,
467
+ base=self._api_root(), json={"modelIds": model_ids}, timeout=300, retry=False,
443
468
  )
444
469
 
445
470
  # ------------------------------------------------------------------
@@ -114,6 +114,10 @@ class MonitorPatternClient:
114
114
  agent_ids=agent_ids,
115
115
  )
116
116
 
117
+ def delete(self, pattern_id: str) -> None:
118
+ """Delete a pattern. Its historical signals remain as history."""
119
+ self._client._request("DELETE", f"/agent-monitoring/patterns/{pattern_id}", base=self._client._api_root())
120
+
117
121
  def get(self, pattern_id: str) -> MonitorPattern:
118
122
  return self._client.get_pattern(pattern_id)
119
123
 
@@ -65,8 +65,10 @@ class ScorerGroupsClient:
65
65
  online: Optional[Dict[str, Any]] = None,
66
66
  ) -> ScorerGroup:
67
67
  """``members``: [{"kind": "judge"|"pattern"|"custom", "refId": ..., "weight": 1, "gate": False}].
68
- ``online``: {"enabled": True, "sampleRate": 0.1, "alertThreshold": 5, "severity": "medium"}
69
- or None for offline-only."""
68
+ ``online``: {"enabled": True, "sampleRate": 0.1, "alertThreshold": 5, "severity": "medium"}.
69
+ Add ``"scope": "session", "idleSeconds": 120`` to score whole multi-turn sessions once
70
+ idle, instead of each sampled trace. Pass ``online=None`` (the default) for a group
71
+ that only grades offline dataset runs."""
70
72
  payload: Dict[str, Any] = {"name": name, "members": members}
71
73
  if description is not None:
72
74
  payload["description"] = description
@@ -19,3 +19,16 @@ class MonitorSessionClient:
19
19
  def spans(self, session_id: str) -> List[dict]:
20
20
  """Every span in the session (roots and children), oldest first."""
21
21
  return self._client.list_session_spans(session_id)
22
+
23
+ def scores(self, session_id: str) -> List[dict]:
24
+ """Session-level verdicts, newest first. ``kind`` says who scored: a session-scoped
25
+ online evaluator (``online-eval:<id>``), a session-scoped scorer group
26
+ (``scorer-group:<id>``), or legacy ``"coherence"`` rows written before the Session
27
+ Baseline Judge existed - branch defensively on unknown kinds."""
28
+ return self._client.list_session_scores(session_id)
29
+
30
+ def run_sweep(self) -> dict:
31
+ """Trigger the idle-session sweep once (normally automatic, every minute) - scores
32
+ idle multi-turn sessions with every enabled session-scoped evaluator and scorer
33
+ group. Returns ``{"judged": n}``."""
34
+ return self._client.run_session_sweep()
@@ -1,7 +1,7 @@
1
- VERSION = "0.8.16"
1
+ VERSION = "0.8.18"
2
2
 
3
3
  # The AgentX-trace-eval release this SDK version is tested against - what `agentx-trace-eval`
4
4
  # installs and converges to (see agentx/cli.py). Bump together with VERSION when releasing, so
5
5
  # every published SDK names a known-good engine+dashboard pair. Users can override with
6
6
  # AGENTX_TRACE_EVAL_VERSION=<tag|latest>.
7
- ENGINE_VERSION = "v0.3.13"
7
+ ENGINE_VERSION = "v0.3.18"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-python
3
- Version: 0.8.16
3
+ Version: 0.8.18
4
4
  Summary: Official Python SDK for AgentX (https://www.agentx.so/)
5
5
  Home-page: https://github.com/AgentX-ai/AgentX-python
6
6
  Author: Robin Wang and AgentX Team
@@ -599,7 +599,9 @@ def test_crewai_captures_real_per_task_timing_via_event_bus():
599
599
  durations are provably unequal — the old "divide latency evenly across
600
600
  tasks" approximation would have reported them as identical.
601
601
  """
602
- crewai = pytest.importorskip("crewai")
602
+ # exc_type=Exception: on older Pythons crewai can raise TypeError (PEP 604 syntax) at
603
+ # import time, and a broken optional integration should skip this test, not fail it.
604
+ crewai = pytest.importorskip("crewai", exc_type=Exception)
603
605
  from crewai.events.event_bus import crewai_event_bus
604
606
  from crewai.events.types.task_events import TaskCompletedEvent, TaskStartedEvent
605
607
  from crewai.tasks.task_output import TaskOutput
@@ -210,12 +210,18 @@ def test_the_fallback_request_gets_the_long_analysis_timeout():
210
210
  {("POST", f"{API_ROOT}/evaluate/analyze/{RUN}"): FakeResponse(200, {"status": "completed"})}
211
211
  )
212
212
 
213
- client.analyze_run(RUN, judges=["gpt-5.5"])
213
+ client.analyze_run(RUN, judges=["gpt-5.6-luna"])
214
214
 
215
215
  method, url, kwargs = session.calls[-1]
216
216
  assert url == f"{API_ROOT}/evaluate/analyze/{RUN}"
217
217
  assert kwargs["timeout"] > 60, "a synchronous judge pass needs more than the 30s default"
218
- assert kwargs["json"]["judges"] == [{"model": "gpt-5.5"}]
218
+ assert kwargs["json"]["judges"] == [{"model": "gpt-5.6-luna"}]
219
+
220
+ # judges=None must OMIT the key - the engine then scores with its platform default model;
221
+ # injecting a hosted-only default (the old "gpt-5.5") produced uncallable judges.
222
+ client.analyze_run(RUN)
223
+ _, _, kwargs = session.calls[-1]
224
+ assert "judges" not in kwargs["json"]
219
225
 
220
226
 
221
227
  # ---------------------------------------------------------------------------
File without changes
File without changes
File without changes
File without changes