applied-cli 0.5.55__tar.gz → 0.5.56__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.55 → applied_cli-0.5.56}/PKG-INFO +1 -1
  2. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/__init__.py +1 -1
  3. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/cli.py +285 -0
  4. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/client.py +135 -0
  5. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/tools.py +205 -0
  6. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli.egg-info/PKG-INFO +1 -1
  7. {applied_cli-0.5.55 → applied_cli-0.5.56}/pyproject.toml +1 -1
  8. {applied_cli-0.5.55 → applied_cli-0.5.56}/README.md +0 -0
  9. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/agent_scoped_flows.py +0 -0
  10. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/conversation_lookup.py +0 -0
  11. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/conversations.py +0 -0
  12. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/credentials.py +0 -0
  13. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/flow_helpers.py +0 -0
  14. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli/formatters.py +0 -0
  15. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli.egg-info/SOURCES.txt +0 -0
  16. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli.egg-info/dependency_links.txt +0 -0
  17. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli.egg-info/entry_points.txt +0 -0
  18. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli.egg-info/requires.txt +0 -0
  19. {applied_cli-0.5.55 → applied_cli-0.5.56}/applied_cli.egg-info/top_level.txt +0 -0
  20. {applied_cli-0.5.55 → applied_cli-0.5.56}/setup.cfg +0 -0
  21. {applied_cli-0.5.55 → applied_cli-0.5.56}/tests/test_agent_scoped_flows.py +0 -0
  22. {applied_cli-0.5.55 → applied_cli-0.5.56}/tests/test_audit_tools.py +0 -0
  23. {applied_cli-0.5.55 → applied_cli-0.5.56}/tests/test_benchmark_scenario_tools.py +0 -0
  24. {applied_cli-0.5.55 → applied_cli-0.5.56}/tests/test_cli.py +0 -0
  25. {applied_cli-0.5.55 → applied_cli-0.5.56}/tests/test_client.py +0 -0
  26. {applied_cli-0.5.55 → applied_cli-0.5.56}/tests/test_conversation_tools.py +0 -0
  27. {applied_cli-0.5.55 → applied_cli-0.5.56}/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.55
3
+ Version: 0.5.56
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.53"
7
+ __version__ = "0.5.56"
8
8
 
9
9
  __all__ = ["AppliedClient", "tools", "to_csv", "to_json", "__version__"]
@@ -1853,6 +1853,291 @@ def connector_types(
1853
1853
  typer.echo(result)
1854
1854
 
1855
1855
 
1856
+ @app.command("agent-update")
1857
+ def agent_update(
1858
+ id: str = typer.Argument(..., help="Agent ID"),
1859
+ name: str = typer.Option(None, "--name", help="Agent name"),
1860
+ prompt: str = typer.Option(None, "--prompt", help="Guidance/guardrails text"),
1861
+ model: str = typer.Option(None, "--model", help="Model name"),
1862
+ modality: str = typer.Option(
1863
+ None, "--modality", help="Modality: Chat, Email, Call, SMS, All"
1864
+ ),
1865
+ agent_type: str = typer.Option(
1866
+ None, "--type", help="Type: Customer Support, Generic, etc."
1867
+ ),
1868
+ escalation_mode: str = typer.Option(
1869
+ None,
1870
+ "--escalation-mode",
1871
+ help="Escalation mode: default, email, sms, email_non_opening_hours, ticketing_integration",
1872
+ ),
1873
+ auto_reply: bool = typer.Option(None, "--auto-reply", help="Enable auto-reply"),
1874
+ metadata: str = typer.Option(
1875
+ None, "--metadata", help="JSON metadata to set on the agent"
1876
+ ),
1877
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
1878
+ ) -> None:
1879
+ """Update an agent."""
1880
+ metadata_dict = _parse_json_option(metadata, option_name="--metadata")
1881
+ client = get_client(shop_id=shop_id)
1882
+ result = asyncio.run(
1883
+ tools.agent_update(
1884
+ client,
1885
+ id,
1886
+ name=name,
1887
+ prompt=prompt,
1888
+ model=model,
1889
+ modality=modality,
1890
+ agent_type=agent_type,
1891
+ escalation_mode=escalation_mode,
1892
+ auto_reply=auto_reply,
1893
+ metadata=metadata_dict,
1894
+ )
1895
+ )
1896
+ typer.echo(result)
1897
+
1898
+
1899
+ @app.command("knowledge-create")
1900
+ def knowledge_create(
1901
+ kb_type: str = typer.Option(
1902
+ ..., "--type", "-t", help="Type: qa, exact, escalate, context, greeting, signature"
1903
+ ),
1904
+ question: str = typer.Option(..., "--question", "-q", help="Trigger text / question"),
1905
+ answer: str = typer.Option(..., "--answer", "-a", help="Response text / answer"),
1906
+ guardrail: str = typer.Option("", "--guardrail", help="Guardrail instructions"),
1907
+ active: bool = typer.Option(True, "--active/--inactive", help="Whether the item is active"),
1908
+ agent_ids: str = typer.Option(
1909
+ None, "--agent-ids", help="Comma-separated agent UUIDs (empty = shop-wide)"
1910
+ ),
1911
+ label_id: str = typer.Option(None, "--label-id", help="Topic label UUID"),
1912
+ flow_id: str = typer.Option(None, "--flow-id", help="Flow UUID to associate with"),
1913
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
1914
+ ) -> None:
1915
+ """Create a knowledge base item."""
1916
+ parsed_agent_ids = _parse_csv_option(agent_ids)
1917
+ client = get_client(shop_id=shop_id)
1918
+ result = asyncio.run(
1919
+ tools.knowledge_create(
1920
+ client,
1921
+ kb_type=kb_type,
1922
+ question=question,
1923
+ answer=answer,
1924
+ guardrail=guardrail,
1925
+ active=active,
1926
+ agent_ids=parsed_agent_ids,
1927
+ label_id=label_id,
1928
+ flow_id=flow_id,
1929
+ )
1930
+ )
1931
+ typer.echo(result)
1932
+
1933
+
1934
+ @app.command("knowledge-update")
1935
+ def knowledge_update(
1936
+ id: str = typer.Argument(..., help="Knowledge item ID"),
1937
+ question: str = typer.Option(None, "--question", "-q", help="Trigger text / question"),
1938
+ answer: str = typer.Option(None, "--answer", "-a", help="Response text / answer"),
1939
+ guardrail: str = typer.Option(None, "--guardrail", help="Guardrail instructions"),
1940
+ active: bool = typer.Option(None, "--active/--inactive", help="Whether the item is active"),
1941
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
1942
+ ) -> None:
1943
+ """Update a knowledge base item."""
1944
+ client = get_client(shop_id=shop_id)
1945
+ result = asyncio.run(
1946
+ tools.knowledge_update(
1947
+ client,
1948
+ id,
1949
+ question=question,
1950
+ answer=answer,
1951
+ guardrail=guardrail,
1952
+ active=active,
1953
+ )
1954
+ )
1955
+ typer.echo(result)
1956
+
1957
+
1958
+ @app.command("product-create")
1959
+ def product_create(
1960
+ title: str = typer.Option(..., "--title", help="Product title"),
1961
+ description: str = typer.Option("", "--description", help="Product description"),
1962
+ url: str = typer.Option("", "--url", help="Product page URL"),
1963
+ images: str = typer.Option(None, "--images", help="Comma-separated image URLs"),
1964
+ price: str = typer.Option(None, "--price", help="Price (e.g. '29.99')"),
1965
+ compare_at_price: str = typer.Option(None, "--compare-at-price", help="Compare-at price"),
1966
+ currency: str = typer.Option("USD", "--currency", help="Currency code"),
1967
+ rating: float = typer.Option(None, "--rating", help="Average rating"),
1968
+ review_count: int = typer.Option(None, "--review-count", help="Number of reviews"),
1969
+ status: str = typer.Option("Active", "--status", help="Status: Active, Draft, Pending"),
1970
+ auto_generate_kb: bool = typer.Option(
1971
+ True, "--auto-generate-kb/--no-auto-generate-kb", help="Auto-generate Q&A"
1972
+ ),
1973
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
1974
+ ) -> None:
1975
+ """Create a product."""
1976
+ parsed_images = _parse_csv_option(images)
1977
+ client = get_client(shop_id=shop_id)
1978
+ result = asyncio.run(
1979
+ tools.product_create(
1980
+ client,
1981
+ title=title,
1982
+ description=description,
1983
+ url=url,
1984
+ images=parsed_images,
1985
+ price=price,
1986
+ compare_at_price=compare_at_price,
1987
+ currency=currency,
1988
+ rating=rating,
1989
+ review_count=review_count,
1990
+ status=status,
1991
+ auto_generate_kb=auto_generate_kb,
1992
+ )
1993
+ )
1994
+ typer.echo(result)
1995
+
1996
+
1997
+ @app.command("taxonomy-create")
1998
+ def taxonomy_create(
1999
+ name: str = typer.Option(..., "--name", "-n", help="Topic or intent name"),
2000
+ parent_id: str = typer.Option(
2001
+ None, "--parent-id", help="Parent topic UUID (if set, creates an intent)"
2002
+ ),
2003
+ color: str = typer.Option(None, "--color", help="Color"),
2004
+ description: str = typer.Option(None, "--description", help="Description"),
2005
+ comments: str = typer.Option(None, "--comments", help="Example queries (3 per line)"),
2006
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2007
+ ) -> None:
2008
+ """Create a topic or intent."""
2009
+ client = get_client(shop_id=shop_id)
2010
+ result = asyncio.run(
2011
+ tools.taxonomy_create(
2012
+ client,
2013
+ name=name,
2014
+ parent_id=parent_id,
2015
+ color=color,
2016
+ description=description,
2017
+ comments=comments,
2018
+ )
2019
+ )
2020
+ typer.echo(result)
2021
+
2022
+
2023
+ @app.command("taxonomy-update")
2024
+ def taxonomy_update(
2025
+ id: str = typer.Argument(..., help="Topic or intent ID"),
2026
+ name: str = typer.Option(None, "--name", "-n", help="Name"),
2027
+ color: str = typer.Option(None, "--color", help="Color"),
2028
+ description: str = typer.Option(None, "--description", help="Description"),
2029
+ comments: str = typer.Option(None, "--comments", help="Example queries"),
2030
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2031
+ ) -> None:
2032
+ """Update a topic or intent."""
2033
+ client = get_client(shop_id=shop_id)
2034
+ result = asyncio.run(
2035
+ tools.taxonomy_update(
2036
+ client,
2037
+ id,
2038
+ name=name,
2039
+ color=color,
2040
+ description=description,
2041
+ comments=comments,
2042
+ )
2043
+ )
2044
+ typer.echo(result)
2045
+
2046
+
2047
+ @app.command("agent-create")
2048
+ def agent_create(
2049
+ name: str = typer.Option(..., "--name", help="Agent name"),
2050
+ modality: str = typer.Option(
2051
+ ..., "--modality", help="Modality: Chat, Email, Call, SMS, All"
2052
+ ),
2053
+ agent_type: str = typer.Option(
2054
+ "Customer Support", "--type", help="Type: Customer Support, Generic, etc."
2055
+ ),
2056
+ model: str = typer.Option("GPT-4.1-mini", "--model", help="Model name"),
2057
+ prompt: str = typer.Option("", "--prompt", help="Guidance/guardrails text"),
2058
+ escalation_mode: str = typer.Option(
2059
+ "default",
2060
+ "--escalation-mode",
2061
+ help="Escalation mode: default, email, sms, email_non_opening_hours, ticketing_integration",
2062
+ ),
2063
+ auto_reply: bool = typer.Option(False, "--auto-reply", help="Enable auto-reply"),
2064
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2065
+ ) -> None:
2066
+ """Create a new agent."""
2067
+ client = get_client(shop_id=shop_id)
2068
+ result = asyncio.run(
2069
+ tools.agent_create(
2070
+ client,
2071
+ name=name,
2072
+ modality=modality,
2073
+ agent_type=agent_type,
2074
+ model=model,
2075
+ prompt=prompt,
2076
+ escalation_mode=escalation_mode,
2077
+ auto_reply=auto_reply,
2078
+ )
2079
+ )
2080
+ typer.echo(result)
2081
+
2082
+
2083
+ @app.command("agent-set-picture")
2084
+ def agent_set_picture(
2085
+ id: str = typer.Argument(..., help="Agent ID"),
2086
+ image: str = typer.Option(
2087
+ ..., "--image", "-i", help="Path to image file (PNG, JPG, etc.)"
2088
+ ),
2089
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2090
+ ) -> None:
2091
+ """Set an agent's profile picture."""
2092
+ client = get_client(shop_id=shop_id)
2093
+ result = asyncio.run(tools.agent_set_picture(client, id, image))
2094
+ typer.echo(result)
2095
+
2096
+
2097
+ @app.command("agent-delete")
2098
+ def agent_delete(
2099
+ id: str = typer.Argument(..., help="Agent ID"),
2100
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2101
+ ) -> None:
2102
+ """Delete an agent."""
2103
+ client = get_client(shop_id=shop_id)
2104
+ result = asyncio.run(tools.agent_delete(client, id))
2105
+ typer.echo(result)
2106
+
2107
+
2108
+ @app.command("knowledge-delete")
2109
+ def knowledge_delete(
2110
+ id: str = typer.Argument(..., help="Knowledge item ID"),
2111
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2112
+ ) -> None:
2113
+ """Delete a knowledge base item."""
2114
+ client = get_client(shop_id=shop_id)
2115
+ result = asyncio.run(tools.knowledge_delete(client, id))
2116
+ typer.echo(result)
2117
+
2118
+
2119
+ @app.command("product-delete")
2120
+ def product_delete(
2121
+ id: str = typer.Argument(..., help="Product ID"),
2122
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2123
+ ) -> None:
2124
+ """Delete a product."""
2125
+ client = get_client(shop_id=shop_id)
2126
+ result = asyncio.run(tools.product_delete(client, id))
2127
+ typer.echo(result)
2128
+
2129
+
2130
+ @app.command("taxonomy-delete")
2131
+ def taxonomy_delete(
2132
+ id: str = typer.Argument(..., help="Topic or intent ID"),
2133
+ shop_id: str = typer.Option(None, "--shop-id", help="Override shop ID"),
2134
+ ) -> None:
2135
+ """Delete a topic or intent."""
2136
+ client = get_client(shop_id=shop_id)
2137
+ result = asyncio.run(tools.taxonomy_delete(client, id))
2138
+ typer.echo(result)
2139
+
2140
+
1856
2141
  def main() -> None:
1857
2142
  """CLI entrypoint."""
1858
2143
  nested_exit_code = run_agent_scoped_flow_command(sys.argv[1:], get_client)
@@ -382,6 +382,50 @@ class AppliedClient:
382
382
  return None
383
383
  return resp.json()
384
384
 
385
+ async def _upload_request(
386
+ self,
387
+ method: str,
388
+ path: str,
389
+ files: dict[str, Any],
390
+ data: dict[str, Any] | None = None,
391
+ ) -> Any:
392
+ """Make an authenticated multipart file upload request."""
393
+ headers = {
394
+ "Authorization": f"Bearer {self.token}",
395
+ }
396
+ if self.shop_id:
397
+ headers["X-Shop-Id"] = self.shop_id
398
+ url = f"{self.base_url}{path}"
399
+
400
+ async with httpx.AsyncClient(timeout=self.timeout) as client:
401
+ resp = await client.request(
402
+ method, url, headers=headers, files=files, data=data or {}
403
+ )
404
+
405
+ if resp.status_code >= 400:
406
+ detail = ""
407
+ try:
408
+ err_data = resp.json()
409
+ if isinstance(err_data, dict):
410
+ detail = str(
411
+ err_data.get("detail")
412
+ or err_data.get("error")
413
+ or err_data.get("message")
414
+ or ""
415
+ )
416
+ except Exception:
417
+ detail = resp.text[:200] if resp.text else ""
418
+
419
+ raise AppliedAPIError(
420
+ message=f"{method} {path} failed",
421
+ status_code=resp.status_code,
422
+ detail=detail,
423
+ )
424
+
425
+ if resp.status_code == 204:
426
+ return None
427
+ return resp.json()
428
+
385
429
  def _require_shop_id(self, shop_id: str | None = None) -> str:
386
430
  resolved_shop_id = shop_id or self.shop_id
387
431
  if not resolved_shop_id:
@@ -431,6 +475,59 @@ class AppliedClient:
431
475
  )
432
476
  return self._normalize_response(data)
433
477
 
478
+ async def create_agent(
479
+ self,
480
+ name: str,
481
+ modality: str,
482
+ agent_type: str = "Customer Support",
483
+ model: str = "GPT-4.1-mini",
484
+ prompt: str = "",
485
+ escalation_mode: str = "default",
486
+ auto_reply: bool = False,
487
+ ) -> dict:
488
+ """Create a new agent."""
489
+ body: dict[str, Any] = {
490
+ "name": name,
491
+ "modality": modality,
492
+ "type": agent_type,
493
+ "model": model,
494
+ "escalation_mode": escalation_mode,
495
+ "auto_reply": auto_reply,
496
+ }
497
+ if prompt:
498
+ body["prompt"] = prompt
499
+ return await self._request("POST", "/v1/agents/", body=body)
500
+
501
+ async def update_agent(
502
+ self,
503
+ agent_id: str,
504
+ **kwargs: Any,
505
+ ) -> dict:
506
+ """Update an agent's properties."""
507
+ return await self._request(
508
+ "PATCH", f"/v1/agents/{agent_id}/", body=kwargs
509
+ )
510
+
511
+ async def update_agent_picture(
512
+ self,
513
+ agent_id: str,
514
+ image_path: str,
515
+ ) -> dict:
516
+ """Update an agent's profile picture via file upload."""
517
+ import mimetypes
518
+
519
+ content_type = mimetypes.guess_type(image_path)[0] or "image/png"
520
+ filename = image_path.rsplit("/", 1)[-1]
521
+ with open(image_path, "rb") as f:
522
+ files = {"profile_picture": (filename, f, content_type)}
523
+ return await self._upload_request(
524
+ "PATCH", f"/v1/agents/{agent_id}/", files=files
525
+ )
526
+
527
+ async def delete_agent(self, agent_id: str) -> None:
528
+ """Delete an agent."""
529
+ await self._request("DELETE", f"/v1/agents/{agent_id}/")
530
+
434
531
  # -------------------------------------------------------------------------
435
532
  # Connector Types
436
533
  # -------------------------------------------------------------------------
@@ -471,6 +568,40 @@ class AppliedClient:
471
568
  data = await self._request("GET", "/v1/property-choices/", params=params)
472
569
  return self._normalize_response(data)
473
570
 
571
+ async def create_taxonomy(
572
+ self,
573
+ name: str,
574
+ parent_id: str | None = None,
575
+ color: str | None = None,
576
+ description: str | None = None,
577
+ comments: str | None = None,
578
+ ) -> dict:
579
+ """Create a topic or intent (property choice)."""
580
+ body: dict[str, Any] = {"name": name}
581
+ if parent_id:
582
+ body["parent_choice_id"] = parent_id
583
+ if color:
584
+ body["color"] = color
585
+ if description:
586
+ body["description"] = description
587
+ if comments:
588
+ body["comments"] = comments
589
+ return await self._request("POST", "/v1/property-choices/", body=body)
590
+
591
+ async def update_taxonomy(
592
+ self,
593
+ choice_id: str,
594
+ **kwargs: Any,
595
+ ) -> dict:
596
+ """Update a topic or intent (property choice)."""
597
+ return await self._request(
598
+ "PATCH", f"/v1/property-choices/{choice_id}/", body=kwargs
599
+ )
600
+
601
+ async def delete_taxonomy(self, choice_id: str) -> None:
602
+ """Delete a topic or intent (property choice)."""
603
+ await self._request("DELETE", f"/v1/property-choices/{choice_id}/")
604
+
474
605
  # -------------------------------------------------------------------------
475
606
  # Analytics
476
607
  # -------------------------------------------------------------------------
@@ -2057,6 +2188,10 @@ class AppliedClient:
2057
2188
  "PATCH", f"/v1/responses/{response_id}/", body=kwargs
2058
2189
  )
2059
2190
 
2191
+ async def delete_response(self, response_id: str) -> None:
2192
+ """Delete a knowledge base item."""
2193
+ await self._request("DELETE", f"/v1/responses/{response_id}/")
2194
+
2060
2195
  # -------------------------------------------------------------------------
2061
2196
  # Products (Content type=Product)
2062
2197
  # -------------------------------------------------------------------------
@@ -5941,3 +5941,208 @@ async def product_delete(
5941
5941
  return _format_error(e)
5942
5942
 
5943
5943
  return f"Product {product_id} deleted successfully."
5944
+
5945
+
5946
+ # -----------------------------------------------------------------------------
5947
+ # Agent - Create / Update / Delete
5948
+ # -----------------------------------------------------------------------------
5949
+
5950
+
5951
+ async def agent_create(
5952
+ client: AppliedClient,
5953
+ name: str,
5954
+ modality: str,
5955
+ agent_type: str = "Customer Support",
5956
+ model: str = "GPT-4.1-mini",
5957
+ prompt: str = "",
5958
+ escalation_mode: str = "default",
5959
+ auto_reply: bool = False,
5960
+ ) -> str:
5961
+ """Create a new agent."""
5962
+ try:
5963
+ agent = await client.create_agent(
5964
+ name=name,
5965
+ modality=modality,
5966
+ agent_type=agent_type,
5967
+ model=model,
5968
+ prompt=prompt,
5969
+ escalation_mode=escalation_mode,
5970
+ auto_reply=auto_reply,
5971
+ )
5972
+ except AppliedAPIError as e:
5973
+ return _format_error(e)
5974
+
5975
+ result = "# Created Agent\n"
5976
+ result += f"id: {agent.get('id')}\n"
5977
+ result += f"name: {agent.get('name')}\n"
5978
+ result += f"modality: {agent.get('modality')}\n"
5979
+ return result
5980
+
5981
+
5982
+ async def agent_update(
5983
+ client: AppliedClient,
5984
+ agent_id: str,
5985
+ name: str | None = None,
5986
+ prompt: str | None = None,
5987
+ model: str | None = None,
5988
+ modality: str | None = None,
5989
+ agent_type: str | None = None,
5990
+ escalation_mode: str | None = None,
5991
+ auto_reply: bool | None = None,
5992
+ metadata: dict | None = None,
5993
+ ) -> str:
5994
+ """Update an agent's properties."""
5995
+ updates: dict = {}
5996
+ if name is not None:
5997
+ updates["name"] = name
5998
+ if prompt is not None:
5999
+ updates["prompt"] = prompt
6000
+ if model is not None:
6001
+ updates["model"] = model
6002
+ if modality is not None:
6003
+ updates["modality"] = modality
6004
+ if agent_type is not None:
6005
+ updates["type"] = agent_type
6006
+ if escalation_mode is not None:
6007
+ updates["escalation_mode"] = escalation_mode
6008
+ if auto_reply is not None:
6009
+ updates["auto_reply"] = auto_reply
6010
+ if metadata is not None:
6011
+ updates["metadata"] = metadata
6012
+
6013
+ try:
6014
+ agent = await client.update_agent(agent_id, **updates)
6015
+ except AppliedAPIError as e:
6016
+ return _format_error(e)
6017
+
6018
+ result = "# Updated Agent\n"
6019
+ result += f"id: {agent.get('id')}\n"
6020
+ result += f"name: {agent.get('name')}\n"
6021
+ result += f"modality: {agent.get('modality')}\n"
6022
+ return result
6023
+
6024
+
6025
+ async def agent_set_picture(
6026
+ client: AppliedClient,
6027
+ agent_id: str,
6028
+ image_path: str,
6029
+ ) -> str:
6030
+ """Set an agent's profile picture from a local file."""
6031
+ import os
6032
+
6033
+ if not os.path.isfile(image_path):
6034
+ return f"Error: File not found: {image_path}"
6035
+
6036
+ try:
6037
+ agent = await client.update_agent_picture(agent_id, image_path)
6038
+ except AppliedAPIError as e:
6039
+ return _format_error(e)
6040
+
6041
+ result = "# Updated Agent Picture\n"
6042
+ result += f"id: {agent.get('id')}\n"
6043
+ result += f"name: {agent.get('name')}\n"
6044
+ result += f"profile_picture: {agent.get('profile_picture')}\n"
6045
+ return result
6046
+
6047
+
6048
+ async def agent_delete(
6049
+ client: AppliedClient,
6050
+ agent_id: str,
6051
+ ) -> str:
6052
+ """Delete an agent."""
6053
+ try:
6054
+ await client.delete_agent(agent_id)
6055
+ except AppliedAPIError as e:
6056
+ return _format_error(e)
6057
+
6058
+ return f"Agent {agent_id} deleted successfully."
6059
+
6060
+
6061
+ # -----------------------------------------------------------------------------
6062
+ # Knowledge Base - Delete
6063
+ # -----------------------------------------------------------------------------
6064
+
6065
+
6066
+ async def knowledge_delete(
6067
+ client: AppliedClient,
6068
+ knowledge_id: str,
6069
+ ) -> str:
6070
+ """Delete a knowledge base item."""
6071
+ try:
6072
+ await client.delete_response(knowledge_id)
6073
+ except AppliedAPIError as e:
6074
+ return _format_error(e)
6075
+
6076
+ return f"Knowledge item {knowledge_id} deleted successfully."
6077
+
6078
+
6079
+ # -----------------------------------------------------------------------------
6080
+ # Taxonomy - Create / Update / Delete
6081
+ # -----------------------------------------------------------------------------
6082
+
6083
+
6084
+ async def taxonomy_create(
6085
+ client: AppliedClient,
6086
+ name: str,
6087
+ parent_id: str | None = None,
6088
+ color: str | None = None,
6089
+ description: str | None = None,
6090
+ comments: str | None = None,
6091
+ ) -> str:
6092
+ """Create a topic or intent."""
6093
+ try:
6094
+ item = await client.create_taxonomy(
6095
+ name=name,
6096
+ parent_id=parent_id,
6097
+ color=color,
6098
+ description=description,
6099
+ comments=comments,
6100
+ )
6101
+ except AppliedAPIError as e:
6102
+ return _format_error(e)
6103
+
6104
+ item_type = "intent" if parent_id else "topic"
6105
+ result = f"# Created {item_type.title()}\n"
6106
+ result += f"id: {item.get('id')}\n"
6107
+ result += f"name: {item.get('name')}\n"
6108
+ return result
6109
+
6110
+
6111
+ async def taxonomy_update(
6112
+ client: AppliedClient,
6113
+ choice_id: str,
6114
+ name: str | None = None,
6115
+ color: str | None = None,
6116
+ description: str | None = None,
6117
+ comments: str | None = None,
6118
+ ) -> str:
6119
+ """Update a topic or intent."""
6120
+ updates: dict = {}
6121
+ if name is not None:
6122
+ updates["name"] = name
6123
+ if color is not None:
6124
+ updates["color"] = color
6125
+ if description is not None:
6126
+ updates["description"] = description
6127
+ if comments is not None:
6128
+ updates["comments"] = comments
6129
+
6130
+ try:
6131
+ item = await client.update_taxonomy(choice_id, **updates)
6132
+ except AppliedAPIError as e:
6133
+ return _format_error(e)
6134
+
6135
+ return f"# Updated Taxonomy Item\nid: {item.get('id')}\nname: {item.get('name')}"
6136
+
6137
+
6138
+ async def taxonomy_delete(
6139
+ client: AppliedClient,
6140
+ choice_id: str,
6141
+ ) -> str:
6142
+ """Delete a topic or intent."""
6143
+ try:
6144
+ await client.delete_taxonomy(choice_id)
6145
+ except AppliedAPIError as e:
6146
+ return _format_error(e)
6147
+
6148
+ return f"Taxonomy item {choice_id} deleted successfully."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: applied-cli
3
- Version: 0.5.55
3
+ Version: 0.5.56
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.55"
3
+ version = "0.5.56"
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"
File without changes
File without changes