cortexdb-connectors 0.2.5__tar.gz → 0.2.7__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.
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/PKG-INFO +1 -1
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/__init__.py +40 -40
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/base.py +39 -10
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/cli.py +584 -583
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/confluence/__init__.py +359 -359
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/discord/__init__.py +646 -646
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/gitlab/__init__.py +749 -749
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/hubspot/__init__.py +489 -489
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/insights/detectors.py +56 -28
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/intercom/__init__.py +631 -631
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/linear/__init__.py +705 -705
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/pagerduty/__init__.py +298 -298
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/salesforce/__init__.py +399 -399
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/servicenow/__init__.py +460 -460
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/slack/__init__.py +103 -11
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/state.py +145 -145
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/teams/__init__.py +656 -656
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/webhooks.py +940 -933
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/worker.py +2 -2
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/zendesk/__init__.py +496 -496
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors.egg-info/PKG-INFO +1 -1
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/pyproject.toml +87 -87
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_base.py +367 -257
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_slack.py +294 -197
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/README.md +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/freshdesk/__init__.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/github/__init__.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/google_workspace/__init__.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/insights/__init__.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/insights/api.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/insights/engine.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/jira/__init__.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/notion/__init__.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors/tldv/__init__.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors.egg-info/SOURCES.txt +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors.egg-info/dependency_links.txt +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors.egg-info/entry_points.txt +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors.egg-info/requires.txt +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/cortexdb_connectors.egg-info/top_level.txt +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/setup.cfg +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_connector_coverage.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_github.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_ingest_e2e.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_streaming_cursor.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_webhooks.py +0 -0
- {cortexdb_connectors-0.2.5 → cortexdb_connectors-0.2.7}/tests/test_webhooks_replay.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cortexdb-connectors
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Data connectors for CortexDB — ingest from Slack, GitHub, GitLab, Jira, Linear, Confluence, Notion, PagerDuty, Discord, Teams, Google Workspace, Salesforce, HubSpot, Zendesk, Intercom, and ServiceNow into the v1 memory API.
|
|
5
5
|
Author-email: CortexDB Team <team@cortexdb.ai>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
"""cortexdb_connectors — data connector SDK for the CortexDB v1 API.
|
|
2
|
-
|
|
3
|
-
Each connector subclass implements `fetch_events`, `normalize`, and
|
|
4
|
-
`map_permissions`; the base class POSTs every normalised Episode to
|
|
5
|
-
`/v1/experience` with the required Authorization + X-Cortex-Actor
|
|
6
|
-
headers. Use the `cortexdb-sync` CLI to run a connector once or in a
|
|
7
|
-
poll loop; or `from cortexdb_connectors.slack import SlackConnector`
|
|
8
|
-
to drive it programmatically.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
__version__ = "0.2.
|
|
12
|
-
|
|
13
|
-
from cortexdb_connectors.base import (
|
|
14
|
-
Actor,
|
|
15
|
-
CortexConnector,
|
|
16
|
-
EntityRef,
|
|
17
|
-
Episode,
|
|
18
|
-
EpisodeType,
|
|
19
|
-
RawEvent,
|
|
20
|
-
Source,
|
|
21
|
-
SyncResult,
|
|
22
|
-
SyncState,
|
|
23
|
-
Visibility,
|
|
24
|
-
VisibilityLevel,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
__all__ = [
|
|
28
|
-
"__version__",
|
|
29
|
-
"Actor",
|
|
30
|
-
"CortexConnector",
|
|
31
|
-
"EntityRef",
|
|
32
|
-
"Episode",
|
|
33
|
-
"EpisodeType",
|
|
34
|
-
"RawEvent",
|
|
35
|
-
"Source",
|
|
36
|
-
"SyncResult",
|
|
37
|
-
"SyncState",
|
|
38
|
-
"Visibility",
|
|
39
|
-
"VisibilityLevel",
|
|
40
|
-
]
|
|
1
|
+
"""cortexdb_connectors — data connector SDK for the CortexDB v1 API.
|
|
2
|
+
|
|
3
|
+
Each connector subclass implements `fetch_events`, `normalize`, and
|
|
4
|
+
`map_permissions`; the base class POSTs every normalised Episode to
|
|
5
|
+
`/v1/experience` with the required Authorization + X-Cortex-Actor
|
|
6
|
+
headers. Use the `cortexdb-sync` CLI to run a connector once or in a
|
|
7
|
+
poll loop; or `from cortexdb_connectors.slack import SlackConnector`
|
|
8
|
+
to drive it programmatically.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__version__ = "0.2.7"
|
|
12
|
+
|
|
13
|
+
from cortexdb_connectors.base import (
|
|
14
|
+
Actor,
|
|
15
|
+
CortexConnector,
|
|
16
|
+
EntityRef,
|
|
17
|
+
Episode,
|
|
18
|
+
EpisodeType,
|
|
19
|
+
RawEvent,
|
|
20
|
+
Source,
|
|
21
|
+
SyncResult,
|
|
22
|
+
SyncState,
|
|
23
|
+
Visibility,
|
|
24
|
+
VisibilityLevel,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"__version__",
|
|
29
|
+
"Actor",
|
|
30
|
+
"CortexConnector",
|
|
31
|
+
"EntityRef",
|
|
32
|
+
"Episode",
|
|
33
|
+
"EpisodeType",
|
|
34
|
+
"RawEvent",
|
|
35
|
+
"Source",
|
|
36
|
+
"SyncResult",
|
|
37
|
+
"SyncState",
|
|
38
|
+
"Visibility",
|
|
39
|
+
"VisibilityLevel",
|
|
40
|
+
]
|
|
@@ -158,6 +158,13 @@ class Episode:
|
|
|
158
158
|
class SyncResult:
|
|
159
159
|
episodes_fetched: int = 0
|
|
160
160
|
episodes_ingested: int = 0
|
|
161
|
+
# Items the connector's content policy deliberately dropped (`normalize`
|
|
162
|
+
# returned None: empty/attachment-only text, emoji-only, noise subtypes).
|
|
163
|
+
# Counted separately so operators can tell "filtered by design" from
|
|
164
|
+
# "failed"; skipped items ADVANCE the cursor like successes — a skip is
|
|
165
|
+
# a decision, not an error, and treating it as one would stall the sync
|
|
166
|
+
# at the first attachment-only message.
|
|
167
|
+
episodes_skipped: int = 0
|
|
161
168
|
errors: list[str] = field(default_factory=list)
|
|
162
169
|
duration_seconds: float = 0.0
|
|
163
170
|
# Watermarks for cursor-safe syncing: the latest source timestamp we
|
|
@@ -237,7 +244,13 @@ class CortexConnector(ABC):
|
|
|
237
244
|
...
|
|
238
245
|
|
|
239
246
|
@abstractmethod
|
|
240
|
-
def normalize(self, raw: RawEvent) -> Episode:
|
|
247
|
+
def normalize(self, raw: RawEvent) -> Episode | None:
|
|
248
|
+
"""Convert a RawEvent into an Episode, or return None to SKIP it.
|
|
249
|
+
|
|
250
|
+
None means the item is dropped by content policy (nothing sent to
|
|
251
|
+
the server); the sync loop counts it in `episodes_skipped` and the
|
|
252
|
+
cursor advances past it.
|
|
253
|
+
"""
|
|
241
254
|
...
|
|
242
255
|
|
|
243
256
|
@abstractmethod
|
|
@@ -257,6 +270,13 @@ class CortexConnector(ABC):
|
|
|
257
270
|
for raw in raw_events:
|
|
258
271
|
try:
|
|
259
272
|
episode = self.normalize(raw)
|
|
273
|
+
if episode is None:
|
|
274
|
+
# Content-policy skip: advance the cursor exactly like a
|
|
275
|
+
# success so the next incremental run never re-fetches it.
|
|
276
|
+
result.episodes_skipped += 1
|
|
277
|
+
if result.latest_success is None or raw.timestamp > result.latest_success:
|
|
278
|
+
result.latest_success = raw.timestamp
|
|
279
|
+
continue
|
|
260
280
|
episode.visibility = self.map_permissions(raw)
|
|
261
281
|
await self.ingest_episode(episode)
|
|
262
282
|
result.episodes_ingested += 1
|
|
@@ -322,19 +342,28 @@ class CortexConnector(ABC):
|
|
|
322
342
|
"role": "user" if modality == "conversation" else "system",
|
|
323
343
|
"text": self._guard_content(episode.content, episode),
|
|
324
344
|
}
|
|
345
|
+
# The v1 write envelope is STRICT (deny_unknown_fields) as of v0.8.0:
|
|
346
|
+
# thread_id / meta / preceded_by are NOT envelope context fields, and
|
|
347
|
+
# sending them returns 422 INVALID_BODY (which stalls the sync cursor
|
|
348
|
+
# forever). Everything routable rides `context.labels` as key=value
|
|
349
|
+
# strings — the queryable partition recall metadata filters target.
|
|
350
|
+
# `context.preceded_by` is a list of CortexDB event ids (evt_…), not
|
|
351
|
+
# source-side parent ids, so the connector's parent_id goes to a
|
|
352
|
+
# label instead.
|
|
353
|
+
labels = list(labels)
|
|
354
|
+
if episode.thread_id:
|
|
355
|
+
labels.append(f"thread={episode.thread_id}")
|
|
356
|
+
if episode.parent_id:
|
|
357
|
+
labels.append(f"parent={episode.parent_id}")
|
|
358
|
+
if episode.metadata:
|
|
359
|
+
for k, v in episode.metadata.items():
|
|
360
|
+
if k == "modality":
|
|
361
|
+
continue
|
|
362
|
+
labels.append(f"{k}={v}")
|
|
325
363
|
context: dict[str, Any] = {
|
|
326
364
|
"observed_at": episode.occurred_at.isoformat(),
|
|
327
365
|
"labels": labels,
|
|
328
366
|
}
|
|
329
|
-
if episode.thread_id:
|
|
330
|
-
context["thread_id"] = episode.thread_id
|
|
331
|
-
if episode.parent_id:
|
|
332
|
-
context["preceded_by"] = [episode.parent_id]
|
|
333
|
-
if episode.metadata:
|
|
334
|
-
# Forward non-reserved metadata under a single key — the v1
|
|
335
|
-
# surface doesn't reject unknown context keys but we tuck
|
|
336
|
-
# everything under `meta` to keep the envelope tidy.
|
|
337
|
-
context["meta"] = {k: v for k, v in episode.metadata.items() if k != "modality"}
|
|
338
367
|
|
|
339
368
|
envelope: dict[str, Any] = {
|
|
340
369
|
"scope": scope,
|