applied-cli 0.5.67__tar.gz → 0.5.69__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.67 → applied_cli-0.5.69}/PKG-INFO +1 -1
  2. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/__init__.py +1 -1
  3. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/agent_scoped_flows.py +10 -13
  4. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/client.py +37 -4
  5. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/tools.py +22 -0
  6. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli.egg-info/PKG-INFO +1 -1
  7. {applied_cli-0.5.67 → applied_cli-0.5.69}/pyproject.toml +1 -1
  8. {applied_cli-0.5.67 → applied_cli-0.5.69}/tests/test_agent_scoped_flows.py +11 -4
  9. {applied_cli-0.5.67 → applied_cli-0.5.69}/README.md +0 -0
  10. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/cli.py +0 -0
  11. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/conversation_lookup.py +0 -0
  12. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/conversations.py +0 -0
  13. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/credentials.py +0 -0
  14. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/flow_helpers.py +0 -0
  15. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli/formatters.py +0 -0
  16. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli.egg-info/SOURCES.txt +0 -0
  17. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli.egg-info/dependency_links.txt +0 -0
  18. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli.egg-info/entry_points.txt +0 -0
  19. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli.egg-info/requires.txt +0 -0
  20. {applied_cli-0.5.67 → applied_cli-0.5.69}/applied_cli.egg-info/top_level.txt +0 -0
  21. {applied_cli-0.5.67 → applied_cli-0.5.69}/setup.cfg +0 -0
  22. {applied_cli-0.5.67 → applied_cli-0.5.69}/tests/test_audit_tools.py +0 -0
  23. {applied_cli-0.5.67 → applied_cli-0.5.69}/tests/test_benchmark_scenario_tools.py +0 -0
  24. {applied_cli-0.5.67 → applied_cli-0.5.69}/tests/test_cli.py +0 -0
  25. {applied_cli-0.5.67 → applied_cli-0.5.69}/tests/test_client.py +0 -0
  26. {applied_cli-0.5.67 → applied_cli-0.5.69}/tests/test_conversation_tools.py +0 -0
  27. {applied_cli-0.5.67 → applied_cli-0.5.69}/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.67
3
+ Version: 0.5.69
4
4
  Summary: CLI and shared client library for Applied Labs AI support agents
5
5
  Author: Applied Labs
6
6
  License-Expression: MIT
@@ -4,6 +4,6 @@ from applied_cli import tools
4
4
  from applied_cli.client import AppliedClient
5
5
  from applied_cli.formatters import to_csv, to_json
6
6
 
7
- __version__ = "0.5.67"
7
+ __version__ = "0.5.69"
8
8
 
9
9
  __all__ = ["AppliedClient", "tools", "to_csv", "to_json", "__version__"]
@@ -42,9 +42,7 @@ def _parse_json_option(value: str | None, *, option_name: str) -> dict[str, Any]
42
42
  ) from exc
43
43
 
44
44
  if not isinstance(parsed, dict):
45
- raise AgentScopedFlowCLIError(
46
- f"{option_name} must decode to a JSON object."
47
- )
45
+ raise AgentScopedFlowCLIError(f"{option_name} must decode to a JSON object.")
48
46
 
49
47
  return parsed
50
48
 
@@ -123,7 +121,9 @@ async def _handle_flow_delete(
123
121
  get_client: Callable[[str | None], AppliedClient],
124
122
  ) -> int:
125
123
  client = get_client(args.shop_id)
126
- flow = await _get_flow_for_agent(client, agent_id=args.agent_id, flow_id=args.flow_id)
124
+ flow = await _get_flow_for_agent(
125
+ client, agent_id=args.agent_id, flow_id=args.flow_id
126
+ )
127
127
  await client.delete_flow(args.flow_id)
128
128
  if args.format == "json":
129
129
  pass
@@ -139,12 +139,6 @@ async def _handle_node_create(
139
139
  client = get_client(args.shop_id)
140
140
  await _get_flow_for_agent(client, agent_id=args.agent_id, flow_id=args.flow_id)
141
141
 
142
- if args.guardrail:
143
- raise AgentScopedFlowCLIError(
144
- "--guardrail is not supported on node create because the API does not "
145
- "persist it. Create the node first, then run node update --guardrail."
146
- )
147
-
148
142
  node = await client.create_node(
149
143
  flow_id=args.flow_id,
150
144
  name=normalize_executor_type(args.executor_type),
@@ -193,11 +187,12 @@ async def _handle_node_delete(
193
187
  get_client: Callable[[str | None], AppliedClient],
194
188
  ) -> int:
195
189
  client = get_client(args.shop_id)
196
- flow = await _get_flow_for_agent(client, agent_id=args.agent_id, flow_id=args.flow_id)
190
+ flow = await _get_flow_for_agent(
191
+ client, agent_id=args.agent_id, flow_id=args.flow_id
192
+ )
197
193
 
198
194
  graph = flow.get("graph") or {}
199
195
  nodes = graph.get("nodes") or []
200
- edges = graph.get("edges") or []
201
196
  node = next((item for item in nodes if item.get("id") == args.node_id), None)
202
197
  if node is None:
203
198
  raise AgentScopedFlowCLIError(
@@ -265,7 +260,9 @@ async def _handle_edge_delete(
265
260
  get_client: Callable[[str | None], AppliedClient],
266
261
  ) -> int:
267
262
  client = get_client(args.shop_id)
268
- flow = await _get_flow_for_agent(client, agent_id=args.agent_id, flow_id=args.flow_id)
263
+ flow = await _get_flow_for_agent(
264
+ client, agent_id=args.agent_id, flow_id=args.flow_id
265
+ )
269
266
 
270
267
  graph = flow.get("graph") or {}
271
268
  edges = graph.get("edges") or []
@@ -1777,6 +1777,10 @@ class AppliedClient:
1777
1777
  },
1778
1778
  )
1779
1779
 
1780
+ async def delete_benchmark(self, benchmark_id: str) -> None:
1781
+ """Delete a benchmark."""
1782
+ await self._request("DELETE", f"/v1/conversation-benchmarks/{benchmark_id}/")
1783
+
1780
1784
  # -------------------------------------------------------------------------
1781
1785
  # Scenarios
1782
1786
  # -------------------------------------------------------------------------
@@ -1786,9 +1790,18 @@ class AppliedClient:
1786
1790
  benchmark_id: str | None = None,
1787
1791
  agent_id: str | None = None,
1788
1792
  pass_status: str | None = None,
1789
- limit: int = 50,
1793
+ limit: int = 200,
1794
+ fetch_all: bool = True,
1790
1795
  ) -> list[dict]:
1791
- """List conversation scenarios."""
1796
+ """List conversation scenarios.
1797
+
1798
+ Args:
1799
+ benchmark_id: Filter by benchmark UUID
1800
+ agent_id: Filter by agent UUID
1801
+ pass_status: Filter by pass status ('pass', 'fail', 'unrated')
1802
+ limit: Page size (default 200)
1803
+ fetch_all: If True, paginate through all results (default True)
1804
+ """
1792
1805
  params: dict[str, Any] = {"limit": limit}
1793
1806
  if benchmark_id:
1794
1807
  params["benchmark_id"] = benchmark_id
@@ -1796,8 +1809,28 @@ class AppliedClient:
1796
1809
  params["agent_id"] = agent_id
1797
1810
  if pass_status:
1798
1811
  params["pass_status"] = pass_status
1799
- data = await self._request("GET", "/v1/conversation-scenarios/", params=params)
1800
- return self._normalize_response(data)
1812
+
1813
+ if not fetch_all:
1814
+ data = await self._request(
1815
+ "GET", "/v1/conversation-scenarios/", params=params
1816
+ )
1817
+ return self._normalize_response(data)
1818
+
1819
+ # Paginate through all results
1820
+ all_results: list[dict] = []
1821
+ page = 1
1822
+ while True:
1823
+ params["page"] = page
1824
+ data = await self._request(
1825
+ "GET", "/v1/conversation-scenarios/", params=params
1826
+ )
1827
+ results = self._normalize_response(data)
1828
+ all_results.extend(results)
1829
+ if isinstance(data, dict) and data.get("next"):
1830
+ page += 1
1831
+ else:
1832
+ break
1833
+ return all_results
1801
1834
 
1802
1835
  async def get_scenario(self, scenario_id: str) -> dict:
1803
1836
  """Get a single scenario by ID."""
@@ -4604,6 +4604,28 @@ async def benchmark_create(
4604
4604
  return result
4605
4605
 
4606
4606
 
4607
+ async def benchmark_delete(
4608
+ client: AppliedClient,
4609
+ benchmark_id: str,
4610
+ ) -> str:
4611
+ """
4612
+ Delete a benchmark.
4613
+
4614
+ Args:
4615
+ client: Authenticated AppliedClient
4616
+ benchmark_id: The benchmark UUID
4617
+
4618
+ Returns:
4619
+ Success message
4620
+ """
4621
+ try:
4622
+ await client.delete_benchmark(benchmark_id)
4623
+ except AppliedAPIError as e:
4624
+ return _format_error(e)
4625
+
4626
+ return f"Benchmark {benchmark_id} deleted successfully."
4627
+
4628
+
4607
4629
  # -----------------------------------------------------------------------------
4608
4630
  # Scenarios
4609
4631
  # -----------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: applied-cli
3
- Version: 0.5.67
3
+ Version: 0.5.69
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.67"
3
+ version = "0.5.69"
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"
@@ -282,7 +282,7 @@ async def test_node_create_prints_raw_json(capsys):
282
282
 
283
283
 
284
284
  @pytest.mark.asyncio
285
- async def test_node_create_rejects_guardrail_on_create():
285
+ async def test_node_create_accepts_guardrail_on_create():
286
286
  client = StubClient()
287
287
  args = _parse_args(
288
288
  [
@@ -299,8 +299,11 @@ async def test_node_create_rejects_guardrail_on_create():
299
299
  ]
300
300
  )
301
301
 
302
- with pytest.raises(AgentScopedFlowCLIError, match="not supported on node create"):
303
- await _handle_node_create(args, lambda _shop_id: client)
302
+ exit_code = await _handle_node_create(args, lambda _shop_id: client)
303
+
304
+ assert exit_code == 0
305
+ assert client.created_node_args is not None
306
+ assert client.created_node_args["guardrail"] == "Be careful"
304
307
 
305
308
 
306
309
  @pytest.mark.asyncio
@@ -347,7 +350,11 @@ async def test_node_update_prints_raw_json(capsys):
347
350
 
348
351
  assert exit_code == 0
349
352
  assert client.updated_node_args == ("flow-1", "node-1", {"prompt": "hi"})
350
- assert json.loads(capsys.readouterr().out) == {**client.node, "id": "node-1", "prompt": "hi"}
353
+ assert json.loads(capsys.readouterr().out) == {
354
+ **client.node,
355
+ "id": "node-1",
356
+ "prompt": "hi",
357
+ }
351
358
 
352
359
 
353
360
  @pytest.mark.asyncio
File without changes
File without changes