cortexdb-connectors 0.2.7__tar.gz → 0.2.9__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 (47) hide show
  1. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/PKG-INFO +1 -1
  2. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/__init__.py +40 -40
  3. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/base.py +29 -9
  4. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/cli.py +609 -584
  5. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/confluence/__init__.py +359 -359
  6. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/discord/__init__.py +646 -646
  7. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/gitlab/__init__.py +749 -749
  8. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/hubspot/__init__.py +489 -489
  9. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/intercom/__init__.py +631 -631
  10. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/jira/__init__.py +112 -14
  11. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/linear/__init__.py +705 -705
  12. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/pagerduty/__init__.py +298 -298
  13. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/salesforce/__init__.py +399 -399
  14. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/servicenow/__init__.py +460 -460
  15. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/state.py +145 -145
  16. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/teams/__init__.py +656 -656
  17. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/webhooks.py +983 -940
  18. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/zendesk/__init__.py +496 -496
  19. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors.egg-info/PKG-INFO +1 -1
  20. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors.egg-info/SOURCES.txt +1 -0
  21. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/pyproject.toml +1 -1
  22. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/tests/test_base.py +416 -367
  23. cortexdb_connectors-0.2.9/tests/test_jira_findings_0_2_9.py +341 -0
  24. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/tests/test_slack.py +294 -294
  25. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/README.md +0 -0
  26. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/freshdesk/__init__.py +0 -0
  27. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/github/__init__.py +0 -0
  28. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/google_workspace/__init__.py +0 -0
  29. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/insights/__init__.py +0 -0
  30. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/insights/api.py +0 -0
  31. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/insights/detectors.py +0 -0
  32. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/insights/engine.py +0 -0
  33. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/notion/__init__.py +0 -0
  34. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/slack/__init__.py +0 -0
  35. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/tldv/__init__.py +0 -0
  36. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors/worker.py +0 -0
  37. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors.egg-info/dependency_links.txt +0 -0
  38. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors.egg-info/entry_points.txt +0 -0
  39. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors.egg-info/requires.txt +0 -0
  40. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/cortexdb_connectors.egg-info/top_level.txt +0 -0
  41. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/setup.cfg +0 -0
  42. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/tests/test_connector_coverage.py +0 -0
  43. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/tests/test_github.py +0 -0
  44. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/tests/test_ingest_e2e.py +0 -0
  45. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/tests/test_streaming_cursor.py +0 -0
  46. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/tests/test_webhooks.py +0 -0
  47. {cortexdb_connectors-0.2.7 → cortexdb_connectors-0.2.9}/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.7
3
+ Version: 0.2.9
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.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
- ]
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.8"
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
+ ]
@@ -13,6 +13,7 @@ from __future__ import annotations
13
13
  import hashlib
14
14
  import logging
15
15
  import os
16
+ import re
16
17
  import uuid
17
18
  from abc import ABC, abstractmethod
18
19
  from dataclasses import dataclass, field
@@ -24,6 +25,11 @@ DEFAULT_API_URL = "https://api-v1.cortexdb.ai"
24
25
 
25
26
  logger = logging.getLogger("cortexdb_connectors")
26
27
 
28
+ # v1 ActorRef grammar (server: cortex-types identity.rs): `kind:local` where
29
+ # kind ∈ _ACTOR_KINDS and local matches [A-Za-z0-9_.@-]+ (no colons!).
30
+ _ACTOR_KINDS = frozenset({"user", "agent", "service", "system"})
31
+ _ACTOR_LOCAL_ILLEGAL = re.compile(r"[^A-Za-z0-9_.@-]")
32
+
27
33
  # Hard ceiling on content size sent to the server. Real items never approach
28
34
  # this; it exists only to stop a pathological payload from exceeding the request
29
35
  # body limit. When it trips we truncate on a UTF-8 boundary and log LOUDLY — we
@@ -96,7 +102,7 @@ class VisibilityLevel(str, Enum):
96
102
  @dataclass(frozen=True)
97
103
  class Source:
98
104
  system: str
99
- connector_version: str = "0.2.5"
105
+ connector_version: str = "0.2.9"
100
106
 
101
107
 
102
108
  @dataclass(frozen=True)
@@ -319,6 +325,17 @@ class CortexConnector(ABC):
319
325
 
320
326
  for key, value in replacements.items():
321
327
  tpl = tpl.replace("{" + key + "}", value or "")
328
+ # C6d: an unresolved placeholder used to pass through literally,
329
+ # producing a silently malformed scope (`.../issue:{entity.issue}`)
330
+ # that the server happily stores as a real path. Fail loudly instead —
331
+ # the sync loop records the error per event and holds the cursor.
332
+ leftover = re.findall(r"\{[^{}]+\}", tpl)
333
+ if leftover:
334
+ raise ValueError(
335
+ f"scope template resolved to {tpl!r} with unresolved "
336
+ f"placeholder(s) {', '.join(leftover)} — this episode does "
337
+ "not carry the referenced entity/field."
338
+ )
322
339
  return tpl
323
340
 
324
341
  def _envelope(self, episode: Episode) -> dict[str, Any]:
@@ -376,14 +393,17 @@ class CortexConnector(ABC):
376
393
  ),
377
394
  }
378
395
  if episode.actor and episode.actor.id:
379
- # v1 ActorRef requires a `kind:id` form (the server rejects a bare
380
- # id with 422: "actor id missing ':' delimiter"). Source actor ids
381
- # (Slack "U123", Jira accountId, …) are bare, so default the kind to
382
- # `user:` unless the connector already supplied a delimiter.
383
- aid = episode.actor.id
384
- if ":" not in aid:
385
- aid = f"user:{aid}"
386
- envelope["observed_actor"] = {"id": aid}
396
+ # Source actor ids are not guaranteed bare: Jira Cloud accountIds
397
+ # are `712020:<uuid>`, so a colon does NOT mean the connector
398
+ # already supplied a kind. Treat the prefix as a kind only when it
399
+ # is one the server accepts; otherwise the whole source id is the
400
+ # local part under `user:`, sanitized to the server's charset
401
+ # (which forbids ':' anywhere in the local part).
402
+ kind, sep, local = episode.actor.id.partition(":")
403
+ if not sep or kind not in _ACTOR_KINDS or not local:
404
+ kind, local = "user", episode.actor.id
405
+ local = _ACTOR_LOCAL_ILLEGAL.sub("_", local)
406
+ envelope["observed_actor"] = {"id": f"{kind}:{local}"}
387
407
 
388
408
  return envelope
389
409