From 5998dcc111908d90f50b688af05d3d27256338bd Mon Sep 17 00:00:00 2001 From: nlathia Date: Tue, 17 Feb 2026 11:56:53 +0000 Subject: [PATCH] Add missing articles apis --- src/gradient_labs/_article_topic_read.py | 33 ++++++++++++++++ src/gradient_labs/_article_topics_list.py | 41 ++++++++++++++++++++ src/gradient_labs/client.py | 27 +++++++++++++ src/gradient_labs/topic.py | 46 +++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 src/gradient_labs/_article_topic_read.py create mode 100644 src/gradient_labs/_article_topics_list.py create mode 100644 src/gradient_labs/topic.py diff --git a/src/gradient_labs/_article_topic_read.py b/src/gradient_labs/_article_topic_read.py new file mode 100644 index 0000000..da0b44c --- /dev/null +++ b/src/gradient_labs/_article_topic_read.py @@ -0,0 +1,33 @@ +from typing import Optional +from dataclasses import dataclass + +from dataclasses_json import dataclass_json + +from .topic import Topic +from ._http_client import HttpClient + + +@dataclass_json +@dataclass(frozen=True) +class ReadTopicParams: + """Parameters for reading a topic.""" + + # support_platform specifies which platform's topic to read. + # Valid values include "public-api" and "intercom". If not provided, + # defaults to "public-api". This allows reading topics from + # different support platforms within the same organization. + support_platform: Optional[str] = None + + +def read_topic( + *, client: HttpClient, topic_id: str, params: Optional[ReadTopicParams] = None +) -> Topic: + """read_topic reads an article topic by ID. + + Note: requires a `Management` API key.""" + query_params = {} + if params and params.support_platform: + query_params["support_platform"] = params.support_platform + + response = client.get(path=f"topic/{topic_id}", query_params=query_params) + return Topic.from_dict(response) diff --git a/src/gradient_labs/_article_topics_list.py b/src/gradient_labs/_article_topics_list.py new file mode 100644 index 0000000..9dd154d --- /dev/null +++ b/src/gradient_labs/_article_topics_list.py @@ -0,0 +1,41 @@ +from typing import List, Optional +from dataclasses import dataclass + +from dataclasses_json import dataclass_json + +from .topic import Topic +from ._http_client import HttpClient + + +@dataclass_json +@dataclass(frozen=True) +class ListTopicsParams: + """Parameters for listing topics.""" + + # support_platform optionally filters topics by support platform. + # Valid values include "public-api" and "intercom". If not provided, + # defaults to "public-api". This allows reading topics from + # different support platforms within the same organization. + support_platform: Optional[str] = None + + +@dataclass_json +@dataclass(frozen=True) +class ListTopicsResponse: + """Response containing a list of topics.""" + + topics: List[Topic] + + +def list_topics( + *, client: HttpClient, params: Optional[ListTopicsParams] = None +) -> ListTopicsResponse: + """list_topics lists a company's topics, optionally filtered by support platform. + + Note: requires a `Management` API key.""" + query_params = {} + if params and params.support_platform: + query_params["support_platform"] = params.support_platform + + response = client.get(path="topics", query_params=query_params) + return ListTopicsResponse.from_dict(response) diff --git a/src/gradient_labs/client.py b/src/gradient_labs/client.py index f6f3a6d..5efb5ec 100644 --- a/src/gradient_labs/client.py +++ b/src/gradient_labs/client.py @@ -3,8 +3,12 @@ from ._article_delete import delete_article from ._article_set_status import set_article_usage_status, SetArticleUsageStatusParams from ._article_topic_upsert import upsert_article_topic, ArticleTopicUpsertParams +from ._article_topic_read import read_topic, ReadTopicParams +from ._article_topics_list import list_topics, ListTopicsParams, ListTopicsResponse from ._article_upsert import upsert_article, UpsertArticleParams +from .topic import Topic + from .conversation import Conversation from ._conversation_add_message import add_message, AddMessageParams, Message from ._conversation_assign import assign_conversation, AssignmentParams @@ -125,6 +129,29 @@ def upsert_article(self, *, params: UpsertArticleParams) -> None: params=params, ) + def list_topics( + self, *, params: Optional[ListTopicsParams] = None + ) -> ListTopicsResponse: + """list_topics lists a company's topics, optionally filtered by support platform. + + Note: requires a `Management` API key.""" + return list_topics( + client=self.http_client, + params=params, + ) + + def read_topic( + self, *, topic_id: str, params: Optional[ReadTopicParams] = None + ) -> Topic: + """read_topic reads an article topic by ID. + + Note: requires a `Management` API key.""" + return read_topic( + client=self.http_client, + topic_id=topic_id, + params=params, + ) + def assign_conversation( self, *, diff --git a/src/gradient_labs/topic.py b/src/gradient_labs/topic.py new file mode 100644 index 0000000..bd8d7f6 --- /dev/null +++ b/src/gradient_labs/topic.py @@ -0,0 +1,46 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Optional, Any + +from dataclasses_json import dataclass_json + +from .article import Visibility + + +@dataclass_json +@dataclass(frozen=True) +class Topic: + """Topic represents an article topic for categorizing help articles.""" + + # source identifies the CRM or support platform that the topic comes from + source: str + + # external_id identifies this topic in the Source + external_id: str + + # name is the human-readable name for this topic + name: str + + # visibility describes who can see the topic + visibility: Visibility + + # created is when the topic was created in the source + created: datetime + + # last_edited is when the topic was last changed in the source + last_edited: datetime + + # last_seen is the last time we saw this topic when crawling + last_seen: datetime + + # data is a raw representation of the topic from the support platform + data: Any + + # description is the optional subtext for the topic + description: Optional[str] = None + + # parent_external_id identifies the topic that this topic is nested under + parent_external_id: Optional[str] = None + + # public_url optionally points to the public resource for this topic + public_url: Optional[str] = None