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.
- zeno_adapters/__init__.py +17 -0
- zeno_adapters/_common.py +38 -0
- zeno_adapters/anthropic.py +68 -0
- zeno_adapters/claude_code.py +101 -0
- zeno_adapters/crewai.py +92 -0
- zeno_adapters/langgraph.py +49 -0
- zeno_adapters/openai.py +108 -0
- zeno_cli/__init__.py +1 -0
- zeno_cli/_hooks/cc_bridge.py +1016 -0
- zeno_cli/doctor.py +535 -0
- zeno_cli/hook_install.py +269 -0
- zeno_cli/hud/__init__.py +1 -0
- zeno_cli/hud/hud_install.py +652 -0
- zeno_cli/hud/zeno_attention.py +288 -0
- zeno_cli/hud/zeno_cognition.py +457 -0
- zeno_cli/hud/zeno_hud.py +496 -0
- zeno_cli/interview_invites.py +342 -0
- zeno_cli/login.py +241 -0
- zeno_cli/main.py +2534 -0
- zeno_cli/onboard.py +206 -0
- zeno_cli/outreach.py +456 -0
- zeno_cli/version.py +67 -0
- zeno_cli-0.3.4.dist-info/METADATA +161 -0
- zeno_cli-0.3.4.dist-info/RECORD +69 -0
- zeno_cli-0.3.4.dist-info/WHEEL +4 -0
- zeno_cli-0.3.4.dist-info/entry_points.txt +4 -0
- zeno_core/__init__.py +67 -0
- zeno_core/analytics.py +193 -0
- zeno_core/rtlx_s.py +460 -0
- zeno_core/streak.py +178 -0
- zeno_core/tlx_s.py +192 -0
- zeno_sdk/__init__.py +6 -0
- zeno_sdk/_generated/__init__.py +6 -0
- zeno_sdk/_generated/client.py +819 -0
- zeno_sdk/_migrations/alembic/env.py +33 -0
- zeno_sdk/_migrations/alembic/script.py.mako +18 -0
- zeno_sdk/_migrations/alembic/versions/0001_initial.py +79 -0
- zeno_sdk/_migrations/alembic/versions/0002_cognition_samples.py +53 -0
- zeno_sdk/_migrations/alembic/versions/0003_cognition_drivers.py +41 -0
- zeno_sdk/_migrations/alembic/versions/0004_transcript_intelligence.py +248 -0
- zeno_sdk/_migrations/alembic.ini +35 -0
- zeno_sdk/_runtime.py +12 -0
- zeno_sdk/adapters/__init__.py +15 -0
- zeno_sdk/adapters/anthropic.py +5 -0
- zeno_sdk/adapters/claude_code.py +5 -0
- zeno_sdk/adapters/crewai.py +5 -0
- zeno_sdk/adapters/langgraph.py +5 -0
- zeno_sdk/adapters/openai.py +5 -0
- zeno_sdk/auth.py +25 -0
- zeno_sdk/client.py +87 -0
- zeno_sdk/config.py +61 -0
- zeno_sdk/daemon.py +72 -0
- zeno_sdk/privacy.py +46 -0
- zeno_sdk/session.py +179 -0
- zeno_sdk/storage.py +487 -0
- zeno_sdk/types/__init__.py +121 -0
- zeno_session_intel/__init__.py +19 -0
- zeno_session_intel/analytics.py +588 -0
- zeno_session_intel/compression.py +123 -0
- zeno_session_intel/ingest.py +376 -0
- zeno_session_intel/model.py +129 -0
- zeno_session_intel/parsers/__init__.py +31 -0
- zeno_session_intel/parsers/claude_code.py +169 -0
- zeno_session_intel/parsers/codex.py +265 -0
- zeno_session_intel/parsers/cursor.py +198 -0
- zeno_session_intel/prices.py +281 -0
- zeno_session_intel/schema.py +277 -0
- zeno_session_intel/signals.py +319 -0
- 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
|
+
]
|
zeno_adapters/_common.py
ADDED
|
@@ -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
|
+
)
|
zeno_adapters/crewai.py
ADDED
|
@@ -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)
|
zeno_adapters/openai.py
ADDED
|
@@ -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."""
|