Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/worktrees/fix-evidence-optional-205
Submodule fix-evidence-optional-205 added at 5516f6
1 change: 1 addition & 0 deletions .claude/worktrees/issue-208
Submodule issue-208 added at a41a2e
1 change: 1 addition & 0 deletions .claude/worktrees/issue-208-frame-tracer-divergence-tests
Submodule issue-208-frame-tracer-divergence-tests added at 5516f6
1 change: 1 addition & 0 deletions .claude/worktrees/issue-208-frame-tracer-tests
Submodule issue-208-frame-tracer-tests added at acdacd
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Type check with pyright
run: |
pip install pyright
pyright || true # Don't fail CI initially, just report
pyright --ignoreexternal

- name: Run tests with coverage
run: |
Expand Down
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Changelog

All notable changes to Peaky Peek will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.19] - 2026-06-13

### Internal
- Deduplicated StrEnum Python 3.10 compatibility shim into `agent_debugger_sdk.core._compat`
- Added composite database indexes for events, sessions, checkpoints
- Replaced module-level `_shared_app` pattern with session-scoped `shared_app` fixture
- Enabled pyright type checking in CI

## [0.1.18] - 2026-06-10

### Fixed
- Corrected stepper test fixture and assertions

### Added
- Agent stepper, swimlane debugger, and violation detection features
- Reasoning editor and divergence detection features

## [0.1.17] - 2026-06-08

### Added
- Research-driven event behavior features
- Frame tracer and divergence detector

### Fixed
- Resolved all ruff lint errors across SDK and test files
- Python 3.10 compatibility for StrEnum in core modules
16 changes: 14 additions & 2 deletions agent_debugger_sdk/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
"""SDK Core module - data models for agent tracing."""
"""SDK Core module - data models for agent tracing.

.. note::
This barrel module re-exports all core types for convenience.
Prefer importing from specific submodules:

- ``agent_debugger_sdk.core.events`` for event types
- ``agent_debugger_sdk.core.context`` for tracing context
- ``agent_debugger_sdk.core.decorators`` for @trace_* decorators
- ``agent_debugger_sdk.core.scorer`` for importance scoring

The barrel import is provided for backward compatibility but will
shrink in a future release.
"""

from agent_debugger_sdk.core.causal_tracer import (
CausalEdge,
Expand Down Expand Up @@ -234,7 +247,6 @@
"EmergentBehaviorType",
"SwimlaneLane",
"MessageFlow",
"CoordinationIssue",
"EmergentBehavior",
"MultiAgentSession",
"analyze_multi_agent_session",
Expand Down
23 changes: 23 additions & 0 deletions agent_debugger_sdk/core/_compat/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Python version compatibility shims for the SDK.

Provides a single source of truth for version-dependent types
so individual modules don't duplicate compat boilerplate.
"""

from __future__ import annotations

import sys
from enum import Enum

if sys.version_info >= (3, 11):
from enum import StrEnum # type: ignore[assignment]
else:

class StrEnum(str, Enum): # type: ignore[misc]
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)


__all__ = ["StrEnum"]
14 changes: 1 addition & 13 deletions agent_debugger_sdk/core/causal_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,11 @@

from __future__ import annotations

import sys
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any

# Python 3.10 compatibility: StrEnum was added in Python 3.11
if sys.version_info >= (3, 11):
from enum import StrEnum # type: ignore[assignment]
else:

class StrEnum(str, Enum): # type: ignore[misc]
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)

from agent_debugger_sdk.core._compat import StrEnum
from agent_debugger_sdk.core.events import EventType, TraceEvent


Expand Down
15 changes: 1 addition & 14 deletions agent_debugger_sdk/core/divergence_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,11 @@

from __future__ import annotations

import sys
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any

# Python 3.10 compatibility: StrEnum was added in Python 3.11
if sys.version_info >= (3, 11):
from enum import StrEnum # type: ignore[assignment]
else:

class StrEnum(str, Enum): # type: ignore[misc]
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)


from agent_debugger_sdk.core._compat import StrEnum
from agent_debugger_sdk.core.events import EventType, TraceEvent

__all__ = [
Expand Down
14 changes: 1 addition & 13 deletions agent_debugger_sdk/core/error_attribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,10 @@

from __future__ import annotations

import sys
from dataclasses import dataclass, field
from enum import Enum
from typing import Any

# Python 3.10 compatibility: StrEnum was added in Python 3.11
if sys.version_info >= (3, 11):
from enum import StrEnum # type: ignore[assignment]
else:

class StrEnum(str, Enum): # type: ignore[misc]
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)

from agent_debugger_sdk.core._compat import StrEnum
from agent_debugger_sdk.core.events import EventType, TraceEvent

__all__ = [
Expand Down
12 changes: 1 addition & 11 deletions agent_debugger_sdk/core/events/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,13 @@

from __future__ import annotations

import sys
import uuid
from dataclasses import asdict, dataclass, field, fields
from datetime import datetime, timezone
from enum import Enum
from typing import Any

# Python 3.10 compatibility: StrEnum was added in Python 3.11
if sys.version_info >= (3, 11):
from enum import StrEnum
else:

class StrEnum(str, Enum):
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)
from agent_debugger_sdk.core._compat import StrEnum


class EventType(StrEnum):
Expand Down
15 changes: 1 addition & 14 deletions agent_debugger_sdk/core/stepper.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,12 @@

from __future__ import annotations

import sys
import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any

# Python 3.10 compatibility: StrEnum was added in Python 3.11
if sys.version_info >= (3, 11):
from enum import StrEnum # type: ignore[assignment]
else:

class StrEnum(str, Enum): # type: ignore[misc]
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)


from agent_debugger_sdk.core._compat import StrEnum
from agent_debugger_sdk.core.events import EventType, TraceEvent

__all__ = [
Expand Down
15 changes: 1 addition & 14 deletions agent_debugger_sdk/core/swimlane.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,12 @@

from __future__ import annotations

import sys
import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any

# Python 3.10 compatibility: StrEnum was added in Python 3.11
if sys.version_info >= (3, 11):
from enum import StrEnum # type: ignore[assignment]
else:

class StrEnum(str, Enum): # type: ignore[misc]
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)


from agent_debugger_sdk.core._compat import StrEnum
from agent_debugger_sdk.core.events import EventType, TraceEvent

__all__ = [
Expand Down
15 changes: 1 addition & 14 deletions agent_debugger_sdk/core/violation_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,12 @@

import math
import re
import sys
from collections import Counter
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any

# Python 3.10 compatibility: StrEnum was added in Python 3.11
if sys.version_info >= (3, 11):
from enum import StrEnum # type: ignore[assignment]
else:

class StrEnum(str, Enum): # type: ignore[misc]
"""Compatibility shim for StrEnum in Python 3.10."""

def __str__(self) -> str:
return str(self.value)


from agent_debugger_sdk.core._compat import StrEnum
from agent_debugger_sdk.core.events import EventType, TraceEvent

__all__ = [
Expand Down
110 changes: 110 additions & 0 deletions agent_debugger_sdk/telemetry/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""
OpenTelemetry integration for Peaky Peek.

Provides optional OTel span export for agent traces, allowing
Peaky Peek sessions to be ingested by Jaeger, Grafana Tempo,
Honeycomb, or any OTel-compatible backend.

Usage::

from agent_debugger_sdk.telemetry import init_telemetry

init_telemetry(
service_name="my-agent",
endpoint="http://localhost:4318", # OTLP gRPC exporter
)

This is entirely optional — if opentelemetry-api is not installed,
all functions are no-ops.
"""

from __future__ import annotations

import logging

logger = logging.getLogger(__name__)

_initialized = False


def init_telemetry(
service_name: str = "peaky-peek-agent",
endpoint: str | None = None,
exporter: str = "console",
) -> None:
"""Initialize OpenTelemetry tracing.

Args:
service_name: Name of the traced service.
endpoint: OTLP exporter endpoint URL. If None, uses console export.
exporter: Exporter type — "console" or "otlp".

If opentelemetry-api/opentelemetry-sdk are not installed, this is a no-op.
"""
global _initialized

try:
from opentelemetry import trace # type: ignore[import-untyped]
from opentelemetry.sdk.trace import TracerProvider # type: ignore[import-untyped]
from opentelemetry.sdk.trace.export import ( # type: ignore[import-untyped]
BatchSpanProcessor,
ConsoleSpanExporter,
)
except ImportError:
logger.info("opentelemetry-sdk not installed — telemetry is disabled")
return

provider = TracerProvider()
trace.set_tracer_provider(provider)

if exporter == "otlp" and endpoint:
try:
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( # type: ignore[import-untyped]
OTLPSpanExporter as GRPCExporter,
)
provider.add_span_processor(
BatchSpanProcessor(GRPCExporter(endpoint=endpoint))
)
except ImportError:
logger.warning("opentelemetry-exporter-otlp not installed — falling back to console export")
provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
else:
provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

_initialized = True
logger.info("Telemetry initialized: service=%s, exporter=%s", service_name, exporter)


def get_tracer(name: str = "peaky-peek", version: str = "1.0.0"):
"""Get an OpenTelemetry tracer.

Returns a no-op tracer if opentelemetry is not installed.
"""
try:
from opentelemetry import trace # type: ignore[import-untyped]

return trace.get_tracer(name, version)
except ImportError:
return _NoOpTracer()


class _NoOpTracer:
"""Minimal no-op tracer for when OTel is not installed."""

def start_as_current_span(self, name: str, **kwargs): # type: ignore[misc]
return _NoOpContextManager()


class _NoOpContextManager:
"""No-op context manager for spans."""

def __enter__(self):
return self

def __exit__(self, *args):
pass


def is_telemetry_enabled() -> bool:
"""Check if telemetry was successfully initialized."""
return _initialized
Loading