applied-cli 0.5.64__tar.gz → 0.5.66__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 (27) hide show
  1. {applied_cli-0.5.64 → applied_cli-0.5.66}/PKG-INFO +1 -1
  2. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/cli.py +10 -1
  3. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/client.py +8 -0
  4. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/tools.py +52 -8
  5. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli.egg-info/PKG-INFO +1 -1
  6. {applied_cli-0.5.64 → applied_cli-0.5.66}/pyproject.toml +1 -1
  7. {applied_cli-0.5.64 → applied_cli-0.5.66}/tests/test_benchmark_scenario_tools.py +3 -0
  8. {applied_cli-0.5.64 → applied_cli-0.5.66}/README.md +0 -0
  9. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/__init__.py +0 -0
  10. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/agent_scoped_flows.py +0 -0
  11. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/conversation_lookup.py +0 -0
  12. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/conversations.py +0 -0
  13. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/credentials.py +0 -0
  14. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/flow_helpers.py +0 -0
  15. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli/formatters.py +0 -0
  16. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli.egg-info/SOURCES.txt +0 -0
  17. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli.egg-info/dependency_links.txt +0 -0
  18. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli.egg-info/entry_points.txt +0 -0
  19. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli.egg-info/requires.txt +0 -0
  20. {applied_cli-0.5.64 → applied_cli-0.5.66}/applied_cli.egg-info/top_level.txt +0 -0
  21. {applied_cli-0.5.64 → applied_cli-0.5.66}/setup.cfg +0 -0
  22. {applied_cli-0.5.64 → applied_cli-0.5.66}/tests/test_agent_scoped_flows.py +0 -0
  23. {applied_cli-0.5.64 → applied_cli-0.5.66}/tests/test_audit_tools.py +0 -0
  24. {applied_cli-0.5.64 → applied_cli-0.5.66}/tests/test_cli.py +0 -0
  25. {applied_cli-0.5.64 → applied_cli-0.5.66}/tests/test_client.py +0 -0
  26. {applied_cli-0.5.64 → applied_cli-0.5.66}/tests/test_conversation_tools.py +0 -0
  27. {applied_cli-0.5.64 → applied_cli-0.5.66}/tests/test_flow_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: applied-cli
3
- Version: 0.5.64
3
+ Version: 0.5.66
4
4
  Summary: CLI and shared client library for Applied Labs AI support agents
5
5
  Author: Applied Labs
6
6
  License-Expression: MIT
@@ -1310,6 +1310,9 @@ def scenario_runs(
1310
1310
  benchmark_id: str = typer.Option(
1311
1311
  None, "--benchmark-id", help="Filter by benchmark ID"
1312
1312
  ),
1313
+ bulk_job_id: str = typer.Option(
1314
+ None, "--bulk-job-id", help="Filter by bulk run job ID"
1315
+ ),
1313
1316
  latest: bool = typer.Option(
1314
1317
  True, "--latest/--all", help="Only show the latest run per scenario"
1315
1318
  ),
@@ -1325,6 +1328,7 @@ def scenario_runs(
1325
1328
  client,
1326
1329
  scenario_id=scenario_id,
1327
1330
  benchmark_id=benchmark_id,
1331
+ bulk_job_id=bulk_job_id,
1328
1332
  latest=latest,
1329
1333
  output_format=format,
1330
1334
  )
@@ -1403,6 +1407,9 @@ def scenario_bulk_run(
1403
1407
  @app.command("scenario-bulk-status")
1404
1408
  def scenario_bulk_status(
1405
1409
  job_id: str = typer.Argument(..., help="Bulk run job ID"),
1410
+ include_runs: bool = typer.Option(
1411
+ False, "--include-runs", help="Include per-run details with scenario mappings"
1412
+ ),
1406
1413
  shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
1407
1414
  format: str = typer.Option(
1408
1415
  "text", "--format", "-f", help="Output format: text or json"
@@ -1411,7 +1418,9 @@ def scenario_bulk_status(
1411
1418
  """Get status for a bulk scenario rerun job."""
1412
1419
  client = get_client(shop_id=shop_id)
1413
1420
  result = asyncio.run(
1414
- tools.scenario_bulk_status(client, job_id=job_id, output_format=format)
1421
+ tools.scenario_bulk_status(
1422
+ client, job_id=job_id, include_runs=include_runs, output_format=format
1423
+ )
1415
1424
  )
1416
1425
  typer.echo(result)
1417
1426
 
@@ -1850,6 +1850,7 @@ class AppliedClient:
1850
1850
  self,
1851
1851
  scenario_id: str | None = None,
1852
1852
  benchmark_id: str | None = None,
1853
+ bulk_job_id: str | None = None,
1853
1854
  latest: bool = False,
1854
1855
  limit: int = 50,
1855
1856
  ) -> list[dict]:
@@ -1859,6 +1860,8 @@ class AppliedClient:
1859
1860
  params["scenario_id"] = scenario_id
1860
1861
  if benchmark_id:
1861
1862
  params["benchmark_id"] = benchmark_id
1863
+ if bulk_job_id:
1864
+ params["bulk_job_id"] = bulk_job_id
1862
1865
  if latest:
1863
1866
  params["latest"] = "true"
1864
1867
  data = await self._request("GET", "/v1/scenario-runs/", params=params)
@@ -1881,6 +1884,7 @@ class AppliedClient:
1881
1884
  scenario_ids: list[str] | None = None,
1882
1885
  benchmark_id: str | None = None,
1883
1886
  target_agent_id: str | None = None,
1887
+ contact_override: dict | None = None,
1884
1888
  ) -> dict:
1885
1889
  """Run multiple scenarios at once.
1886
1890
 
@@ -1888,6 +1892,8 @@ class AppliedClient:
1888
1892
  scenario_ids: List of scenario UUIDs to run
1889
1893
  benchmark_id: Run all scenarios in this benchmark
1890
1894
  target_agent_id: Optional agent to run against (for A/B testing)
1895
+ contact_override: Optional contact override dict, e.g.
1896
+ {"mode": "contact", "contact_id": "<uuid>"}
1891
1897
  """
1892
1898
  body: dict[str, Any] = {}
1893
1899
  if scenario_ids:
@@ -1896,6 +1902,8 @@ class AppliedClient:
1896
1902
  body["benchmark_id"] = benchmark_id
1897
1903
  if target_agent_id:
1898
1904
  body["target_agent_id"] = target_agent_id
1905
+ if contact_override:
1906
+ body["contact_override"] = contact_override
1899
1907
  return await self._request("POST", "/v1/scenario-runs/bulk-run/", body=body)
1900
1908
 
1901
1909
  async def get_scenario_bulk_run_status(self, job_id: str) -> dict:
@@ -200,7 +200,15 @@ def _project_scenario_payload(
200
200
 
201
201
 
202
202
  def _project_scenario_run_payload(run: dict) -> dict:
203
- scenario = run.get("scenario") or {}
203
+ # scenario can be a UUID string (PK) or a nested dict
204
+ scenario_raw = run.get("scenario")
205
+ if isinstance(scenario_raw, dict):
206
+ scenario_id = scenario_raw.get("id")
207
+ scenario_name = scenario_raw.get("name")
208
+ else:
209
+ scenario_id = scenario_raw
210
+ scenario_name = run.get("scenario_name")
211
+
204
212
  evaluated_by = run.get("evaluated_by") or {}
205
213
  return {
206
214
  "id": run.get("id"),
@@ -219,8 +227,8 @@ def _project_scenario_run_payload(run: dict) -> dict:
219
227
  "evaluated_by_id": evaluated_by.get("id"),
220
228
  "evaluated_by_name": evaluated_by.get("name"),
221
229
  "scenario": {
222
- "id": scenario.get("id"),
223
- "name": scenario.get("name"),
230
+ "id": scenario_id,
231
+ "name": scenario_name,
224
232
  },
225
233
  "output_conversation": _project_embedded_conversation(
226
234
  run.get("output_conversation")
@@ -4786,6 +4794,7 @@ async def scenario_run_list(
4786
4794
  client: AppliedClient,
4787
4795
  scenario_id: str | None = None,
4788
4796
  benchmark_id: str | None = None,
4797
+ bulk_job_id: str | None = None,
4789
4798
  latest: bool = True,
4790
4799
  output_format: str = "csv",
4791
4800
  ) -> str:
@@ -4796,19 +4805,30 @@ async def scenario_run_list(
4796
4805
  client: Authenticated AppliedClient
4797
4806
  scenario_id: Optional - filter by scenario UUID
4798
4807
  benchmark_id: Optional - filter by benchmark UUID
4808
+ bulk_job_id: Optional - filter by bulk run job UUID
4799
4809
  latest: If True, show only the most recent run per scenario (default True)
4800
4810
  output_format: 'csv' or 'json'
4801
4811
 
4802
4812
  Returns:
4803
- List of scenario runs with id, scenario_name, pass_status, csat_score
4813
+ List of scenario runs with id, scenario_id, scenario_name, pass_status, output_conversation_id
4804
4814
  """
4805
4815
  runs = await client.list_scenario_runs(
4806
- scenario_id=scenario_id, benchmark_id=benchmark_id, latest=latest
4816
+ scenario_id=scenario_id,
4817
+ benchmark_id=benchmark_id,
4818
+ bulk_job_id=bulk_job_id,
4819
+ latest=latest,
4807
4820
  )
4821
+ def _extract_scenario_fields(r: dict) -> tuple:
4822
+ scenario_raw = r.get("scenario")
4823
+ if isinstance(scenario_raw, dict):
4824
+ return scenario_raw.get("id", ""), scenario_raw.get("name", "")
4825
+ return scenario_raw or "", r.get("scenario_name", "")
4826
+
4808
4827
  mapped = [
4809
4828
  {
4810
4829
  "id": r.get("id"),
4811
- "scenario_name": r.get("scenario", {}).get("name", ""),
4830
+ "scenario_id": _extract_scenario_fields(r)[0],
4831
+ "scenario_name": _extract_scenario_fields(r)[1],
4812
4832
  "status": r.get("status"),
4813
4833
  "pass_status": r.get("pass_status", "unrated"),
4814
4834
  "csat_score": r.get("csat_score"),
@@ -4825,6 +4845,7 @@ async def scenario_run_list(
4825
4845
  mapped,
4826
4846
  [
4827
4847
  "id",
4848
+ "scenario_id",
4828
4849
  "scenario_name",
4829
4850
  "status",
4830
4851
  "pass_status",
@@ -4917,6 +4938,7 @@ async def scenario_bulk_run(
4917
4938
  scenario_ids: list[str] | None = None,
4918
4939
  benchmark_id: str | None = None,
4919
4940
  target_agent_id: str | None = None,
4941
+ contact_override: dict | None = None,
4920
4942
  output_format: str = "text",
4921
4943
  ) -> str:
4922
4944
  """
@@ -4927,6 +4949,7 @@ async def scenario_bulk_run(
4927
4949
  scenario_ids: List of scenario UUIDs to run
4928
4950
  benchmark_id: Run all scenarios in this benchmark
4929
4951
  target_agent_id: Optional agent to run against (for A/B testing)
4952
+ contact_override: Optional contact override, e.g. {"mode": "contact", "contact_id": "<uuid>"}
4930
4953
 
4931
4954
  Returns:
4932
4955
  Summary of runs created
@@ -4954,6 +4977,7 @@ async def scenario_bulk_run(
4954
4977
  result = await client.bulk_run_scenarios(
4955
4978
  scenario_ids=resolved_scenario_ids,
4956
4979
  target_agent_id=target_agent_id,
4980
+ contact_override=contact_override,
4957
4981
  )
4958
4982
  except AppliedAPIError as e:
4959
4983
  return _format_error(e)
@@ -4987,12 +5011,14 @@ async def scenario_bulk_run(
4987
5011
  output += f"scenario_run_ids: {preview_ids}\n"
4988
5012
  if len(run_ids) > 10:
4989
5013
  output += f"more_runs: {len(run_ids) - 10}\n"
5014
+ output += f"\nTip: use scenario_bulk_status(job_id, include_runs=True) or scenario_run_list(bulk_job_id=job_id) to get per-run details with scenario mappings."
4990
5015
  return output
4991
5016
 
4992
5017
 
4993
5018
  async def scenario_bulk_status(
4994
5019
  client: AppliedClient,
4995
5020
  job_id: str,
5021
+ include_runs: bool = False,
4996
5022
  output_format: str = "text",
4997
5023
  ) -> str:
4998
5024
  """
@@ -5001,10 +5027,11 @@ async def scenario_bulk_status(
5001
5027
  Args:
5002
5028
  client: Authenticated AppliedClient
5003
5029
  job_id: The bulk run job UUID
5030
+ include_runs: If True, include per-run details (scenario_id, output_conversation_id, status)
5004
5031
  output_format: 'text' (default) or 'json'
5005
5032
 
5006
5033
  Returns:
5007
- Counts, timing information, and failed run details
5034
+ Counts, timing information, failed run details, and optionally per-run details
5008
5035
  """
5009
5036
  try:
5010
5037
  result = await client.get_scenario_bulk_run_status(job_id)
@@ -5012,7 +5039,10 @@ async def scenario_bulk_status(
5012
5039
  return _format_error(e)
5013
5040
 
5014
5041
  if output_format == "json":
5015
- return to_json(result)
5042
+ payload = dict(result)
5043
+ if not include_runs:
5044
+ payload.pop("runs", None)
5045
+ return to_json(payload)
5016
5046
 
5017
5047
  counts = result.get("counts") or {}
5018
5048
  output = "# Bulk Run Status\n"
@@ -5034,6 +5064,20 @@ async def scenario_bulk_status(
5034
5064
  output += f"\n# Failed Runs ({len(failed)})\n"
5035
5065
  output += to_json(failed)
5036
5066
 
5067
+ runs_detail = result.get("runs") or []
5068
+ if include_runs and runs_detail:
5069
+ output += f"\n\n# Per-Run Details ({len(runs_detail)})\n"
5070
+ output += to_csv(
5071
+ runs_detail,
5072
+ [
5073
+ "id",
5074
+ "scenario_id",
5075
+ "status",
5076
+ "pass_status",
5077
+ "output_conversation_id",
5078
+ ],
5079
+ )
5080
+
5037
5081
  return output
5038
5082
 
5039
5083
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: applied-cli
3
- Version: 0.5.64
3
+ Version: 0.5.66
4
4
  Summary: CLI and shared client library for Applied Labs AI support agents
5
5
  Author: Applied Labs
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "applied-cli"
3
- version = "0.5.64"
3
+ version = "0.5.66"
4
4
  description = "CLI and shared client library for Applied Labs AI support agents"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -231,11 +231,13 @@ class FakeScenarioClient:
231
231
  scenario_ids=None,
232
232
  benchmark_id=None,
233
233
  target_agent_id=None,
234
+ contact_override=None,
234
235
  ):
235
236
  self.bulk_run_kwargs = {
236
237
  "scenario_ids": scenario_ids,
237
238
  "benchmark_id": benchmark_id,
238
239
  "target_agent_id": target_agent_id,
240
+ "contact_override": contact_override,
239
241
  }
240
242
  return {
241
243
  "job_id": "job-1",
@@ -351,6 +353,7 @@ async def test_scenario_bulk_run_resolves_ids_from_benchmark():
351
353
  "scenario_ids": ["scenario-1"],
352
354
  "benchmark_id": None,
353
355
  "target_agent_id": "agent-2",
356
+ "contact_override": None,
354
357
  }
355
358
  assert payload["benchmark_id"] == "bench-1"
356
359
  assert payload["scenario_run_ids"] == ["scenario-run-1"]
File without changes
File without changes