zeno-cli 0.3.4__py3-none-any.whl

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 (69) hide show
  1. zeno_adapters/__init__.py +17 -0
  2. zeno_adapters/_common.py +38 -0
  3. zeno_adapters/anthropic.py +68 -0
  4. zeno_adapters/claude_code.py +101 -0
  5. zeno_adapters/crewai.py +92 -0
  6. zeno_adapters/langgraph.py +49 -0
  7. zeno_adapters/openai.py +108 -0
  8. zeno_cli/__init__.py +1 -0
  9. zeno_cli/_hooks/cc_bridge.py +1016 -0
  10. zeno_cli/doctor.py +535 -0
  11. zeno_cli/hook_install.py +269 -0
  12. zeno_cli/hud/__init__.py +1 -0
  13. zeno_cli/hud/hud_install.py +652 -0
  14. zeno_cli/hud/zeno_attention.py +288 -0
  15. zeno_cli/hud/zeno_cognition.py +457 -0
  16. zeno_cli/hud/zeno_hud.py +496 -0
  17. zeno_cli/interview_invites.py +342 -0
  18. zeno_cli/login.py +241 -0
  19. zeno_cli/main.py +2534 -0
  20. zeno_cli/onboard.py +206 -0
  21. zeno_cli/outreach.py +456 -0
  22. zeno_cli/version.py +67 -0
  23. zeno_cli-0.3.4.dist-info/METADATA +161 -0
  24. zeno_cli-0.3.4.dist-info/RECORD +69 -0
  25. zeno_cli-0.3.4.dist-info/WHEEL +4 -0
  26. zeno_cli-0.3.4.dist-info/entry_points.txt +4 -0
  27. zeno_core/__init__.py +67 -0
  28. zeno_core/analytics.py +193 -0
  29. zeno_core/rtlx_s.py +460 -0
  30. zeno_core/streak.py +178 -0
  31. zeno_core/tlx_s.py +192 -0
  32. zeno_sdk/__init__.py +6 -0
  33. zeno_sdk/_generated/__init__.py +6 -0
  34. zeno_sdk/_generated/client.py +819 -0
  35. zeno_sdk/_migrations/alembic/env.py +33 -0
  36. zeno_sdk/_migrations/alembic/script.py.mako +18 -0
  37. zeno_sdk/_migrations/alembic/versions/0001_initial.py +79 -0
  38. zeno_sdk/_migrations/alembic/versions/0002_cognition_samples.py +53 -0
  39. zeno_sdk/_migrations/alembic/versions/0003_cognition_drivers.py +41 -0
  40. zeno_sdk/_migrations/alembic/versions/0004_transcript_intelligence.py +248 -0
  41. zeno_sdk/_migrations/alembic.ini +35 -0
  42. zeno_sdk/_runtime.py +12 -0
  43. zeno_sdk/adapters/__init__.py +15 -0
  44. zeno_sdk/adapters/anthropic.py +5 -0
  45. zeno_sdk/adapters/claude_code.py +5 -0
  46. zeno_sdk/adapters/crewai.py +5 -0
  47. zeno_sdk/adapters/langgraph.py +5 -0
  48. zeno_sdk/adapters/openai.py +5 -0
  49. zeno_sdk/auth.py +25 -0
  50. zeno_sdk/client.py +87 -0
  51. zeno_sdk/config.py +61 -0
  52. zeno_sdk/daemon.py +72 -0
  53. zeno_sdk/privacy.py +46 -0
  54. zeno_sdk/session.py +179 -0
  55. zeno_sdk/storage.py +487 -0
  56. zeno_sdk/types/__init__.py +121 -0
  57. zeno_session_intel/__init__.py +19 -0
  58. zeno_session_intel/analytics.py +588 -0
  59. zeno_session_intel/compression.py +123 -0
  60. zeno_session_intel/ingest.py +376 -0
  61. zeno_session_intel/model.py +129 -0
  62. zeno_session_intel/parsers/__init__.py +31 -0
  63. zeno_session_intel/parsers/claude_code.py +169 -0
  64. zeno_session_intel/parsers/codex.py +265 -0
  65. zeno_session_intel/parsers/cursor.py +198 -0
  66. zeno_session_intel/prices.py +281 -0
  67. zeno_session_intel/schema.py +277 -0
  68. zeno_session_intel/signals.py +319 -0
  69. zeno_session_intel/taxonomy.py +71 -0
@@ -0,0 +1,17 @@
1
+ """Adapter package exports."""
2
+
3
+ from .anthropic import instrument as instrument_anthropic
4
+ from .claude_code import instrument as instrument_claude_code
5
+ from .crewai import instrument_agent as instrument_crewai_agent
6
+ from .crewai import instrument_crew as instrument_crewai_crew
7
+ from .langgraph import instrument as instrument_langgraph
8
+ from .openai import instrument as instrument_openai
9
+
10
+ __all__ = [
11
+ "instrument_anthropic",
12
+ "instrument_claude_code",
13
+ "instrument_crewai_agent",
14
+ "instrument_crewai_crew",
15
+ "instrument_langgraph",
16
+ "instrument_openai",
17
+ ]
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from collections.abc import Callable
5
+ from typing import Any
6
+
7
+
8
+ def _get(obj: Any, key: str, default: Any = None) -> Any:
9
+ if isinstance(obj, dict):
10
+ return obj.get(key, default)
11
+ return getattr(obj, key, default)
12
+
13
+
14
+ def _tool_names_from_anthropic(result: Any) -> list[str]:
15
+ content = _get(result, "content", [])
16
+ names: list[str] = []
17
+ for item in content or []:
18
+ if _get(item, "type") == "tool_use":
19
+ name = _get(item, "name")
20
+ if isinstance(name, str):
21
+ names.append(name)
22
+ return names
23
+
24
+
25
+ def _extract_usage(result: Any) -> tuple[int | None, int | None]:
26
+ usage = _get(result, "usage")
27
+ if usage is None:
28
+ return (None, None)
29
+ input_tokens = _get(usage, "input_tokens")
30
+ output_tokens = _get(usage, "output_tokens")
31
+ return (input_tokens, output_tokens)
32
+
33
+
34
+ def call_with_timing(fn: Callable[..., Any], *args: Any, **kwargs: Any) -> tuple[Any, int]:
35
+ started = time.perf_counter_ns()
36
+ result = fn(*args, **kwargs)
37
+ latency_ms = int((time.perf_counter_ns() - started) / 1_000_000)
38
+ return result, max(latency_ms, 0)
@@ -0,0 +1,68 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from ._common import _extract_usage, _tool_names_from_anthropic, call_with_timing
7
+
8
+
9
+ @dataclass(slots=True)
10
+ class _MessagesProxy:
11
+ inner: Any
12
+ zeno_session: Any
13
+ record_content: bool = False
14
+
15
+ def create(self, *args: Any, **kwargs: Any) -> Any:
16
+ model = kwargs.get("model", "unknown")
17
+ with self.zeno_session.agent_run(model=model) as run:
18
+ try:
19
+ result, latency_ms = call_with_timing(self.inner.create, *args, **kwargs)
20
+ input_tokens, output_tokens = _extract_usage(result)
21
+ metadata: dict[str, Any] = {
22
+ "provider": "anthropic",
23
+ "harness": "anthropic",
24
+ "input_tokens": input_tokens,
25
+ "output_tokens": output_tokens,
26
+ "tool_names": _tool_names_from_anthropic(result),
27
+ "tool_call_count": len(_tool_names_from_anthropic(result)),
28
+ }
29
+ if self.record_content:
30
+ metadata["prompt"] = str(kwargs.get("messages"))
31
+ metadata["output"] = str(getattr(result, "content", None))
32
+
33
+ self.zeno_session.record(
34
+ type="accept",
35
+ latency_ms_to_decide=latency_ms,
36
+ metadata=metadata,
37
+ )
38
+ run.outcome("accepted")
39
+ return result
40
+ except Exception:
41
+ self.zeno_session.record(
42
+ type="reject",
43
+ metadata={"provider": "anthropic", "harness": "anthropic"},
44
+ )
45
+ run.outcome("rejected")
46
+ raise
47
+
48
+
49
+ @dataclass(slots=True)
50
+ class _ClientProxy:
51
+ client: Any
52
+ zeno_session: Any
53
+ record_content: bool = False
54
+
55
+ @property
56
+ def messages(self) -> _MessagesProxy:
57
+ return _MessagesProxy(
58
+ inner=self.client.messages,
59
+ zeno_session=self.zeno_session,
60
+ record_content=self.record_content,
61
+ )
62
+
63
+ def __getattr__(self, item: str) -> Any:
64
+ return getattr(self.client, item)
65
+
66
+
67
+ def instrument(client: Any, *, zeno_session: Any, record_content: bool = False) -> Any:
68
+ return _ClientProxy(client=client, zeno_session=zeno_session, record_content=record_content)
@@ -0,0 +1,101 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from ._common import _extract_usage, _tool_names_from_anthropic, call_with_timing
7
+
8
+
9
+ def _trace_metadata(tracer: Any) -> dict[str, Any]:
10
+ if tracer is None:
11
+ return {"trace_event_count": 0, "trace_event_types": []}
12
+ events = tracer.get_recent_events()
13
+ event_types = sorted(
14
+ {
15
+ event.get("type")
16
+ for event in events
17
+ if isinstance(event, dict) and isinstance(event.get("type"), str)
18
+ }
19
+ )
20
+ return {
21
+ "trace_event_count": len(events),
22
+ "trace_event_types": event_types,
23
+ }
24
+
25
+
26
+ @dataclass(slots=True)
27
+ class _MessagesProxy:
28
+ inner: Any
29
+ tracer: Any
30
+ zeno_session: Any
31
+ record_content: bool = False
32
+
33
+ def create(self, *args: Any, **kwargs: Any) -> Any:
34
+ model = kwargs.get("model", "unknown")
35
+ with self.zeno_session.agent_run(model=model) as run:
36
+ try:
37
+ result, latency_ms = call_with_timing(self.inner.create, *args, **kwargs)
38
+ input_tokens, output_tokens = _extract_usage(result)
39
+ tool_names = _tool_names_from_anthropic(result)
40
+ metadata: dict[str, Any] = {
41
+ "provider": "anthropic",
42
+ "harness": "claude-code",
43
+ "input_tokens": input_tokens,
44
+ "output_tokens": output_tokens,
45
+ "tool_names": tool_names,
46
+ "tool_call_count": len(tool_names),
47
+ }
48
+ metadata.update(_trace_metadata(self.tracer))
49
+ if self.record_content:
50
+ metadata["prompt"] = str(kwargs.get("messages"))
51
+ metadata["output"] = str(getattr(result, "content", None))
52
+
53
+ self.zeno_session.record(
54
+ type="accept",
55
+ latency_ms_to_decide=latency_ms,
56
+ metadata=metadata,
57
+ )
58
+ run.outcome("accepted")
59
+ return result
60
+ except Exception:
61
+ self.zeno_session.record(
62
+ type="reject",
63
+ metadata={"provider": "anthropic", "harness": "claude-code"},
64
+ )
65
+ run.outcome("rejected")
66
+ raise
67
+
68
+
69
+ @dataclass(slots=True)
70
+ class _ClientProxy:
71
+ client: Any
72
+ tracer: Any
73
+ zeno_session: Any
74
+ record_content: bool = False
75
+
76
+ @property
77
+ def messages(self) -> _MessagesProxy:
78
+ return _MessagesProxy(
79
+ inner=self.client.messages,
80
+ tracer=self.tracer,
81
+ zeno_session=self.zeno_session,
82
+ record_content=self.record_content,
83
+ )
84
+
85
+ def __getattr__(self, item: str) -> Any:
86
+ return getattr(self.client, item)
87
+
88
+
89
+ def instrument(
90
+ client: Any,
91
+ *,
92
+ tracer: Any,
93
+ zeno_session: Any,
94
+ record_content: bool = False,
95
+ ) -> Any:
96
+ return _ClientProxy(
97
+ client=client,
98
+ tracer=tracer,
99
+ zeno_session=zeno_session,
100
+ record_content=record_content,
101
+ )
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from ._common import call_with_timing
7
+
8
+
9
+ @dataclass(slots=True)
10
+ class InstrumentedAgent:
11
+ inner: Any
12
+ zeno_session: Any
13
+ model: str = "crewai-agent"
14
+ record_content: bool = False
15
+
16
+ def run(self, *args: Any, **kwargs: Any) -> Any:
17
+ with self.zeno_session.agent_run(model=self.model) as run:
18
+ try:
19
+ result, latency_ms = call_with_timing(self.inner.run, *args, **kwargs)
20
+ metadata: dict[str, Any] = {
21
+ "provider": "crewai",
22
+ "harness": "crewai",
23
+ "tool_call_count": int(getattr(result, "tool_call_count", 0)),
24
+ "tool_names": list(getattr(result, "tool_names", [])),
25
+ "status": getattr(result, "status", "success"),
26
+ }
27
+ if self.record_content:
28
+ metadata["prompt"] = str(kwargs.get("task") or kwargs.get("input"))
29
+ metadata["output"] = str(getattr(result, "output", None))
30
+ self.zeno_session.record(
31
+ type="accept",
32
+ latency_ms_to_decide=latency_ms,
33
+ metadata=metadata,
34
+ )
35
+ run.outcome("accepted")
36
+ return result
37
+ except Exception:
38
+ self.zeno_session.record(
39
+ type="reject",
40
+ metadata={"provider": "crewai", "harness": "crewai"},
41
+ )
42
+ run.outcome("rejected")
43
+ raise
44
+
45
+ def __getattr__(self, item: str) -> Any:
46
+ return getattr(self.inner, item)
47
+
48
+
49
+ @dataclass(slots=True)
50
+ class InstrumentedCrew:
51
+ inner: Any
52
+ zeno_session: Any
53
+ model: str = "crewai-crew"
54
+ record_content: bool = False
55
+
56
+ def kickoff(self, *args: Any, **kwargs: Any) -> Any:
57
+ with self.zeno_session.agent_run(model=self.model) as run:
58
+ try:
59
+ result, latency_ms = call_with_timing(self.inner.kickoff, *args, **kwargs)
60
+ metadata: dict[str, Any] = {
61
+ "provider": "crewai",
62
+ "harness": "crewai",
63
+ "status": "kickoff",
64
+ }
65
+ if self.record_content:
66
+ metadata["prompt"] = str(kwargs.get("inputs"))
67
+ metadata["output"] = str(result)
68
+ self.zeno_session.record(
69
+ type="accept",
70
+ latency_ms_to_decide=latency_ms,
71
+ metadata=metadata,
72
+ )
73
+ run.outcome("accepted")
74
+ return result
75
+ except Exception:
76
+ self.zeno_session.record(
77
+ type="reject",
78
+ metadata={"provider": "crewai", "harness": "crewai"},
79
+ )
80
+ run.outcome("rejected")
81
+ raise
82
+
83
+ def __getattr__(self, item: str) -> Any:
84
+ return getattr(self.inner, item)
85
+
86
+
87
+ def instrument_agent(agent: Any, *, zeno_session: Any, record_content: bool = False) -> Any:
88
+ return InstrumentedAgent(inner=agent, zeno_session=zeno_session, record_content=record_content)
89
+
90
+
91
+ def instrument_crew(crew: Any, *, zeno_session: Any, record_content: bool = False) -> Any:
92
+ return InstrumentedCrew(inner=crew, zeno_session=zeno_session, record_content=record_content)
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from ._common import call_with_timing
7
+
8
+
9
+ @dataclass(slots=True)
10
+ class InstrumentedGraph:
11
+ inner: Any
12
+ zeno_session: Any
13
+ model: str = "langgraph"
14
+ record_content: bool = False
15
+
16
+ def invoke(self, *args: Any, **kwargs: Any) -> Any:
17
+ with self.zeno_session.agent_run(model=self.model) as run:
18
+ try:
19
+ result, latency_ms = call_with_timing(self.inner.invoke, *args, **kwargs)
20
+ metadata: dict[str, Any] = {
21
+ "provider": "langgraph",
22
+ "harness": "langgraph",
23
+ "node_count": int(getattr(result, "node_count", 0)),
24
+ "tool_call_count": int(getattr(result, "tool_call_count", 0)),
25
+ }
26
+ if self.record_content:
27
+ metadata["prompt"] = str(kwargs.get("input") or args[0] if args else "")
28
+ metadata["output"] = str(result)
29
+ self.zeno_session.record(
30
+ type="accept",
31
+ latency_ms_to_decide=latency_ms,
32
+ metadata=metadata,
33
+ )
34
+ run.outcome("accepted")
35
+ return result
36
+ except Exception:
37
+ self.zeno_session.record(
38
+ type="reject",
39
+ metadata={"provider": "langgraph", "harness": "langgraph"},
40
+ )
41
+ run.outcome("rejected")
42
+ raise
43
+
44
+ def __getattr__(self, item: str) -> Any:
45
+ return getattr(self.inner, item)
46
+
47
+
48
+ def instrument(graph: Any, *, zeno_session: Any, record_content: bool = False) -> Any:
49
+ return InstrumentedGraph(inner=graph, zeno_session=zeno_session, record_content=record_content)
@@ -0,0 +1,108 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from ._common import _extract_usage, call_with_timing
7
+
8
+
9
+ def _tool_names_from_openai(result: Any) -> list[str]:
10
+ tool_names: list[str] = []
11
+ output = getattr(result, "output", None)
12
+ if output is None and isinstance(result, dict):
13
+ output = result.get("output")
14
+ for item in output or []:
15
+ item_type = item.get("type") if isinstance(item, dict) else getattr(item, "type", None)
16
+ if item_type == "tool_call":
17
+ name = item.get("name") if isinstance(item, dict) else getattr(item, "name", None)
18
+ if isinstance(name, str):
19
+ tool_names.append(name)
20
+ return tool_names
21
+
22
+
23
+ @dataclass(slots=True)
24
+ class _CreateProxy:
25
+ inner: Any
26
+ zeno_session: Any
27
+ provider: str
28
+ record_content: bool = False
29
+
30
+ def create(self, *args: Any, **kwargs: Any) -> Any:
31
+ model = kwargs.get("model", "unknown")
32
+ with self.zeno_session.agent_run(model=model) as run:
33
+ try:
34
+ result, latency_ms = call_with_timing(self.inner.create, *args, **kwargs)
35
+ input_tokens, output_tokens = _extract_usage(result)
36
+ tool_names = _tool_names_from_openai(result)
37
+ metadata: dict[str, Any] = {
38
+ "provider": "openai",
39
+ "harness": self.provider,
40
+ "input_tokens": input_tokens,
41
+ "output_tokens": output_tokens,
42
+ "tool_names": tool_names,
43
+ "tool_call_count": len(tool_names),
44
+ }
45
+ if self.record_content:
46
+ metadata["prompt"] = str(kwargs.get("messages") or kwargs.get("input"))
47
+ metadata["output"] = str(getattr(result, "output", None))
48
+ self.zeno_session.record(
49
+ type="accept",
50
+ latency_ms_to_decide=latency_ms,
51
+ metadata=metadata,
52
+ )
53
+ run.outcome("accepted")
54
+ return result
55
+ except Exception:
56
+ self.zeno_session.record(
57
+ type="reject",
58
+ metadata={"provider": "openai", "harness": self.provider},
59
+ )
60
+ run.outcome("rejected")
61
+ raise
62
+
63
+
64
+ @dataclass(slots=True)
65
+ class _ChatProxy:
66
+ inner: Any
67
+ zeno_session: Any
68
+ record_content: bool = False
69
+
70
+ @property
71
+ def completions(self) -> _CreateProxy:
72
+ return _CreateProxy(
73
+ inner=self.inner.completions,
74
+ zeno_session=self.zeno_session,
75
+ provider="openai-chat",
76
+ record_content=self.record_content,
77
+ )
78
+
79
+
80
+ @dataclass(slots=True)
81
+ class _ClientProxy:
82
+ client: Any
83
+ zeno_session: Any
84
+ record_content: bool = False
85
+
86
+ @property
87
+ def responses(self) -> _CreateProxy:
88
+ return _CreateProxy(
89
+ inner=self.client.responses,
90
+ zeno_session=self.zeno_session,
91
+ provider="openai-responses",
92
+ record_content=self.record_content,
93
+ )
94
+
95
+ @property
96
+ def chat(self) -> _ChatProxy:
97
+ return _ChatProxy(
98
+ inner=self.client.chat,
99
+ zeno_session=self.zeno_session,
100
+ record_content=self.record_content,
101
+ )
102
+
103
+ def __getattr__(self, item: str) -> Any:
104
+ return getattr(self.client, item)
105
+
106
+
107
+ def instrument(client: Any, *, zeno_session: Any, record_content: bool = False) -> Any:
108
+ return _ClientProxy(client=client, zeno_session=zeno_session, record_content=record_content)
zeno_cli/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """Zeno CLI package placeholder."""