Skip to content
Merged
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Below is the list of packages currently included in this repository.
| [`packages/bub-acp-server`](./packages/bub-acp-server/README.md) | `acp-server` | Exposes Bub as an Agent Client Protocol agent with `bub acp serve` for ACP-compatible editors. |
| [`packages/bub-tg-feed`](./packages/bub-tg-feed/README.md) | `tg-feed` | Provides an AMQP-based channel adapter for Telegram feed messages. |
| [`packages/bub-schedule`](./packages/bub-schedule/README.md) | `schedule` | Provides scheduling channel/tools backed by APScheduler with a JSON job store. |
| [`packages/bub-tapestore-otel`](./packages/bub-tapestore-otel/README.md) | `tapestore-otel` | Wraps the active tape store and projects committed tape writes to OpenTelemetry through Logfire. |
| [`packages/bub-tapestore-sqlalchemy`](./packages/bub-tapestore-sqlalchemy/README.md) | `tapestore-sqlalchemy` | Provides a SQLAlchemy-backed tape store for Bub conversation history. |
| [`packages/bub-tapestore-sqlite`](./packages/bub-tapestore-sqlite/README.md) | `tapestore-sqlite` | Provides a SQLite-backed tape store for Bub conversation history. |
| [`packages/bub-discord`](./packages/bub-discord/README.md) | `discord` | Provides a Discord channel adapter for Bub message IO. |
Expand Down
77 changes: 77 additions & 0 deletions packages/bub-tapestore-otel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# bub-tapestore-otel

`bub-tapestore-otel` wraps the active Bub tape store and projects committed tape
writes to OpenTelemetry through the OTLP HTTP exporter.

It is a transparent tape-store decorator:

```text
Bub -> OTelTapeStore -> active TapeStore
-> OpenTelemetry / OTLP
```

The real tape backend can still be the builtin file store or another contrib
store such as SQLite, SQLAlchemy, or Redis. This package observes `append` and
`reset` calls after the real store succeeds, then emits best-effort spans. Export
failures are swallowed so telemetry cannot break tape persistence.

## Configuration

For local Phoenix:

```bash
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1:6006/v1/traces \
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf \
uv run bub run "hello"
```

For local Jaeger:

```bash
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://127.0.0.1:4318/v1/traces \
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf \
uv run bub run "hello"
```

Plugin settings:

| Variable | Default | Description |
| --- | --- | --- |
| `BUB_TAPESTORE_OTEL_ENABLED` | `true` | Wrap the active tape store. |
| `BUB_TAPESTORE_OTEL_SERVICE_NAME` | `bub` | OpenTelemetry `service.name` resource value. |
| `BUB_TAPESTORE_OTEL_AGENT_NAME` | `bub` | OpenTelemetry `gen_ai.agent.name` value. |

OTLP exporter configuration stays on the standard OpenTelemetry environment
variables such as `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` and
`OTEL_EXPORTER_OTLP_TRACES_PROTOCOL`.

The projection is tape-first and uses separate namespaces for separate
semantic sources:

- `gen_ai.*` attributes and span names follow the current OpenTelemetry GenAI
semantic conventions.
- `bub.*` attributes describe Bub-specific runtime facts such as tape identity,
tape entry boundaries, loop step number, step duration, and the runtime tool
name Bub actually executed.
- `openinference.*`, `llm.*`, `input.*`, and `output.*` attributes are emitted
as Phoenix/OpenInference compatibility attributes so Phoenix can classify and
render Bub spans usefully. They are not OpenTelemetry semantic-convention
attributes.

It emits these spans:

- `invoke_agent bub` root span with `gen_ai.operation.name=invoke_agent`,
`gen_ai.agent.name=bub`, and `openinference.span.kind=AGENT`
- `bub.agent.step` framework span for each Bub loop turn, carrying custom
`bub.agent.step` and `bub.agent.step.duration_ms` attributes
- `chat <model>` child span with `gen_ai.operation.name=chat` and
`openinference.span.kind=LLM`
- `execute_tool <name>` child spans with `gen_ai.operation.name=execute_tool`,
`gen_ai.tool.call.*`, `bub.tool.*`, and `openinference.span.kind=TOOL`

All spans include `gen_ai.conversation.id` for trace correlation. Message
content, system prompt, token usage, model/provider metadata, and tool calls are
derived from committed tape entries and exported using OTel GenAI and
OpenInference attribute names. Bub loop turns do not currently have a dedicated
OTel GenAI semantic-convention attribute, so step numbering stays in the
`bub.*` namespace.
22 changes: 22 additions & 0 deletions packages/bub-tapestore-otel/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[project]
name = "bub-tapestore-otel"
version = "0.1.0"
description = "OpenTelemetry projection layer for Bub tape stores"
readme = "README.md"
authors = [
{ name = "Chojan Shang", email = "psiace@apache.org" }
]
requires-python = ">=3.12"
dependencies = [
"bub",
"opentelemetry-exporter-otlp-proto-http>=1.39.0",
"opentelemetry-sdk>=1.39.0",
"republic>=0.5.7",
]

[project.entry-points.bub]
tapestore-otel = "bub_tapestore_otel.plugin:OTelTapeStorePlugin"

[build-system]
requires = ["uv_build>=0.9.7,<0.10.0"]
build-backend = "uv_build"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from __future__ import annotations

__all__ = ["OTelTapeStorePlugin"]

from bub_tapestore_otel.plugin import OTelTapeStorePlugin
Loading