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
7 changes: 7 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# OpenTelemetry local export settings
ENABLE_OTEL=true
OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317
OTEL_SERVICE_NAME=prompt-orchestrator
OTEL_SERVICE_NAMESPACE=prompt-stack
OTEL_DEPLOYMENT_ENVIRONMENT=dev
OTEL_UPSTREAM_OTLP_ENDPOINT=host.docker.internal:4317
81 changes: 81 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,87 @@ For development and tests:
pip install -e .[dev]
```

Install with optional OpenTelemetry support:

```bash
pip install -e .[otel]
```

## Optional OpenTelemetry + SigNoz

OpenTelemetry is optional. If not installed or not enabled, PromptOrchestrator works as before.

SigNoz is expected to run separately (for example, official SigNoz Docker deployment on `http://localhost:8080`).

Enable OTel (host runtime):

```bash
ENABLE_OTEL=true
OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317
OTEL_SERVICE_NAME=prompt-orchestrator
OTEL_SERVICE_NAMESPACE=prompt-stack
OTEL_DEPLOYMENT_ENVIRONMENT=dev
```

Required/optional flags summary:

- Start telemetry export (required): set `ENABLE_OTEL=true`
- Stop telemetry export (required): set `ENABLE_OTEL=false`
- OTLP destination (optional, used when enabled): `OTEL_EXPORTER_OTLP_ENDPOINT`
- Resource labels (optional): `OTEL_SERVICE_NAME`, `OTEL_SERVICE_NAMESPACE`, `OTEL_DEPLOYMENT_ENVIRONMENT`, `OTEL_SERVICE_VERSION`

Run local OTel Collector (1 additional container):

```bash
docker compose -f docker-compose.otel.yml up -d
```

Disable OTel (host runtime):

```bash
ENABLE_OTEL=false
```

Stop local OTel Collector:

```bash
docker compose -f docker-compose.otel.yml down
```

Files used:

- `docker-compose.otel.yml`
- `observability/otel-collector-config.yaml`

Default endpoints:

- SigNoz UI (external): `http://localhost:8080`
- OTLP gRPC ingest (local collector): `http://localhost:4317`
- OTLP HTTP ingest (local collector): `http://localhost:4318`

Exposed telemetry (when enabled):

| Telemetry signal name | Description |
| --- | --- |
| `prompt_orchestrator.build_for_request` | Trace span for one prompt build request. Includes attribute `session.id`. |
| `prompt_build_requests_total` | Counter of prompt build attempts. Attributes include `operation=build_for_request` and `status` (`ok`/`error`). |
| `prompt_errors_total` | Counter of errors by operation and error type. Attributes include `operation` and `error.type`. |
| `prompt_build_latency_ms` | Histogram of prompt build latency in milliseconds. |
| `prompt_total_tokens` | Histogram of total token count in the built prompt payload. |
| `prompt_total_chars` | Histogram of total character count in the built prompt payload. |
| `prompt_rag_chunks_count` | Histogram of retrieved RAG chunks used in the prompt. |
| `prompt_warnings_count` | Histogram of analyzer warnings count per build. |
| `prompt_safety_events_total` | Counter of safety events. Attributes include `severity` and `status`. |
| `prompt_summary_calls_total` | Counter of summary calls. Attributes include `operation=summary`, `provider`, and `status`. |
| `prompt_summary_latency_ms` | Histogram of summary call latency in milliseconds. |
| `prompt.error operation={operation} error_type={error_type}` | OTLP log message emitted on errors (for example in `build_for_request` or `summary`). |

Dashboard template blueprint:

- `observability/signoz-dashboard-prompt-orchestrator.yaml`

Use it as a panel/query blueprint in SigNoz to create a dashboard for prompt build latency, token pressure, RAG payload size, safety events, summary latency, logs, and traces.

## Configuration Models

- `PromptConfig`: static prompt structure
Expand Down
14 changes: 14 additions & 0 deletions docker-compose.otel.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:0.103.0
command: ["--config=/etc/otelcol/config.yaml"]
environment:
OTEL_UPSTREAM_OTLP_ENDPOINT: "${OTEL_UPSTREAM_OTLP_ENDPOINT:-host.docker.internal:4317}"
volumes:
- ./observability/otel-collector-config.yaml:/etc/otelcol/config.yaml:ro
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "4317:4317"
- "4318:4318"
restart: unless-stopped
29 changes: 29 additions & 0 deletions observability/otel-collector-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
receivers:
otlp:
protocols:
grpc:
http:

processors:
batch:

exporters:
otlp:
endpoint: ${OTEL_UPSTREAM_OTLP_ENDPOINT}
tls:
insecure: true

service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
86 changes: 86 additions & 0 deletions observability/signoz-dashboard-prompt-orchestrator.import.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"title": "PromptOrchestrator Overview",
"description": "Importable dashboard for PromptOrchestrator OTel metrics.",
"tags": ["signoz", "otel", "prompt-orchestrator"],
"timezone": "browser",
"schemaVersion": 39,
"version": 1,
"panels": [
{
"title": "Build Requests",
"type": "timeseries",
"targets": [
{
"expr": "sum(rate(prompt_build_requests_total{service_name=~\"$service\",deployment_environment=~\"$env\"}[5m]))",
"legendFormat": "build req/s"
}
]
},
{
"title": "Build Errors",
"type": "timeseries",
"targets": [
{
"expr": "sum(rate(prompt_errors_total{service_name=~\"$service\",deployment_environment=~\"$env\"}[5m])) by (operation)",
"legendFormat": "{{operation}}"
}
]
},
{
"title": "Build Latency P95",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(prompt_build_latency_ms_bucket{service_name=~\"$service\",deployment_environment=~\"$env\"}[5m])) by (le))",
"legendFormat": "p95"
}
]
},
{
"title": "Prompt Tokens P50",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(prompt_total_tokens_bucket{service_name=~\"$service\",deployment_environment=~\"$env\"}[5m])) by (le))",
"legendFormat": "p50"
}
]
},
{
"title": "Safety Events",
"type": "barchart",
"targets": [
{
"expr": "sum(rate(prompt_safety_events_total{service_name=~\"$service\",deployment_environment=~\"$env\"}[5m])) by (severity)",
"legendFormat": "{{severity}}"
}
]
},
{
"title": "Summary Latency P95",
"type": "timeseries",
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(prompt_summary_latency_ms_bucket{service_name=~\"$service\",deployment_environment=~\"$env\"}[5m])) by (le, provider))",
"legendFormat": "{{provider}} p95"
}
]
}
],
"templating": {
"list": [
{
"name": "env",
"type": "custom",
"query": "dev,stage,prod",
"current": { "text": "dev", "value": "dev" }
},
{
"name": "service",
"type": "custom",
"query": "prompt-orchestrator",
"current": { "text": "prompt-orchestrator", "value": "prompt-orchestrator" }
}
]
}
}
51 changes: 51 additions & 0 deletions observability/signoz-dashboard-prompt-orchestrator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
dashboard:
title: PromptOrchestrator Overview
description: SigNoz dashboard blueprint for PromptOrchestrator metrics exported through OpenTelemetry.
variables:
- name: env
description: deployment.environment resource attribute
default: dev
- name: service
description: service.name resource attribute
default: prompt-orchestrator
panels:
- title: Build Requests
type: time_series
unit: req/s
query: sum(rate(prompt_build_requests_total{service_name="$service",deployment_environment="$env"}[5m]))
- title: Build Errors
type: time_series
unit: err/s
query: sum(rate(prompt_errors_total{service_name="$service",deployment_environment="$env"}[5m])) by (operation)
- title: Build Latency P95
type: time_series
unit: ms
query: histogram_quantile(0.95, sum(rate(prompt_build_latency_ms_bucket{service_name="$service",deployment_environment="$env"}[5m])) by (le))
- title: Prompt Tokens P50
type: time_series
unit: tokens
query: histogram_quantile(0.50, sum(rate(prompt_total_tokens_bucket{service_name="$service",deployment_environment="$env"}[5m])) by (le))
- title: Prompt Chars P50
type: time_series
unit: chars
query: histogram_quantile(0.50, sum(rate(prompt_total_chars_bucket{service_name="$service",deployment_environment="$env"}[5m])) by (le))
- title: RAG Chunks per Build
type: time_series
unit: chunks
query: histogram_quantile(0.50, sum(rate(prompt_rag_chunks_count_bucket{service_name="$service",deployment_environment="$env"}[5m])) by (le))
- title: Warnings per Build
type: time_series
unit: warnings
query: histogram_quantile(0.95, sum(rate(prompt_warnings_count_bucket{service_name="$service",deployment_environment="$env"}[5m])) by (le))
- title: Safety Events
type: bar
unit: events/s
query: sum(rate(prompt_safety_events_total{service_name="$service",deployment_environment="$env"}[5m])) by (severity)
- title: Summary Latency P95
type: time_series
unit: ms
query: histogram_quantile(0.95, sum(rate(prompt_summary_latency_ms_bucket{service_name="$service",deployment_environment="$env"}[5m])) by (le, provider))
logs:
default_query: service.name = "$service" AND deployment.environment = "$env"
traces:
span_filter: service.name = "$service" and name = "prompt_orchestrator.build_for_request"
19 changes: 11 additions & 8 deletions prompt_orchestrator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
"""Prompt orchestration package."""

from .analyzer.analyzer import PromptAnalyzer
from .builder.builder import PromptBuilder
from .cache.base import CacheBackend, NoCacheBackend
from .cache.local_ttl import LocalTTLCacheBackend
from .config.config_store import ConfigStore
from .config.module_config import ModuleConfig
from .config.prompt_config import PromptConfig
from .config.settings import OrchestratorSettings
from .context.manager import PromptContextManager
from .context.state import DocChunk, Message, PromptContextState
from .cache.base import CacheBackend, NoCacheBackend
from .cache.local_ttl import LocalTTLCacheBackend
from .rag.base import RAGProvider
from .rag.no_rag import NoRAGProvider
from .llm.ollama_client import OllamaConfig, OllamaSummaryClient
from .llm.openai_client import OpenAIConfig, OpenAISummaryClient
from .llm.summary_llm import SummaryLLM, SummaryLLMConfig
from .safety.engine import PromptSafetyEngine
from .analyzer.analyzer import PromptAnalyzer
from .builder.builder import PromptBuilder
from .context.manager import PromptContextManager
from .orchestrator.factory import PromptOrchestratorFactory
from .orchestrator.orchestrator import OrchestratedPrompt, PromptOrchestrator
from .rag.base import RAGProvider
from .rag.no_rag import NoRAGProvider
from .safety.engine import PromptSafetyEngine
from .telemetry import init_telemetry, shutdown_telemetry
from .tokenization import TokenCounter

__all__ = [
Expand Down Expand Up @@ -47,4 +48,6 @@
"SummaryLLM",
"SummaryLLMConfig",
"TokenCounter",
"init_telemetry",
"shutdown_telemetry",
]
2 changes: 1 addition & 1 deletion prompt_orchestrator/cache/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .base import CacheBackend, NoCacheBackend
from .cornet_cache import CornetCacheBackend
from .local_ttl import LocalTTLCacheBackend
from .redis_cache import RedisCacheBackend
from .cornet_cache import CornetCacheBackend

__all__ = [
"CacheBackend",
Expand Down
2 changes: 1 addition & 1 deletion prompt_orchestrator/context/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .state import DocChunk, Message, PromptContextState
from .manager import PromptContextManager
from .state import DocChunk, Message, PromptContextState

__all__ = ["DocChunk", "Message", "PromptContextManager", "PromptContextState"]
Loading
Loading