@propermotion/virgo-observe
v0.3.0
Published
Virgo Observe instrumentation for JavaScript and TypeScript agent frameworks
Downloads
1,878
Maintainers
Readme
@propermotion/virgo-observe
Virgo Observe instrumentation for server-side JavaScript and TypeScript agent
frameworks. Version 0.3.0 supports the following exact framework packages:
| Package | Version | Node requirement |
| ---------------------------------------- | ------------------------- | ---------------- |
| @earendil-works/pi-coding-agent | 0.84.3 | 22.19+ |
| @mariozechner/pi-coding-agent (legacy) | 0.73.1 | 20.6+ |
| eve | 0.52.2 with [email protected] | 24+ |
Pi moved from @mariozechner to @earendil-works. Install Observe alongside
the application's existing Pi package; no Pi replacement or downgrade is needed.
The two Pi peers are independently optional, including in TypeScript declarations.
It captures Pi's effective system instructions and each model turn's conversation,
including tool results. It reuses existing deployment settings and labels missing
environments unspecified.
Before importing a framework adapter, inspect compatibility without loading that framework:
import { assessFrameworkCompatibility } from "@propermotion/virgo-observe";
const report = assessFrameworkCompatibility("eve", "0.39.3");
// report.status === "blocked"; report.candidate.assessment === "unknown"
const pi = assessFrameworkCompatibility(
"@earendil-works/pi-coding-agent",
"0.84.3",
);
// pi.status === "supported"; pi.candidate === nullPass the actual resolved version from the application's lock/runtime, not its
declared range. For Pi, pass the actual installed package name; the older "pi"
alias continues to mean @mariozechner/pi-coding-agent. null means unknown.
The report names the package, installed
version, supported range, blocked capability, runtime requirements, and exact
candidate commands for npm, pnpm, Yarn, and Bun. Choose the owning package's
manager and dependency group. Eve's registrationReport().compatibility contains
the same assessment using the framework version supplied to setup. Older Eve
versions may never discover the experimental provider, so run preflight first.
Candidate commands are proposals; no dependency is changed. Their assessment
stays unknown until the coding host checks the actual manifest/lock, peer and
companion constraints, official migration notes, call sites, and focused behavior
tests in a disposable environment. Satisfying the adapter gate alone does not
prove an application upgrade safe. Known API/configuration changes must be
reported as migration-required; exact application checks can establish
verified-compatible only for the tested revision and paths. Continue independent
supported instrumentation when another capability is blocked.
Use Virgo's Trace with Virgo-Observe bootstrap flow first. Both adapters load
the Observe key and destination from the ignored .virgo/observe.env in the
project directory. In deployments, set VIRGO_API_KEY; VIRGO_ENDPOINT is only
needed for a custom Virgo deployment. No workspace ID belongs in application code.
Eve
npm install @propermotion/[email protected]Enable the provider layout in the existing agent configuration:
// agent/agent.ts — keep the existing model and other settings
export default defineAgent({
// ...existing settings
experimental: { instrumentationProviders: true },
});Add one file:
// agent/instrumentation/virgo.ts
export { default } from "@propermotion/virgo-observe/eve";Eve currently marks this provider API experimental. Its provider directory and
the older agent/instrumentation.ts file are mutually exclusive. If the older
file already exists, migrate its destinations into provider files before enabling
the flag. Keep any other experimental settings already present in defineAgent.
Do not send a second copy of Eve's native model spans to the same Virgo source.
Run Eve normally. For explicit configuration and registration diagnostics:
import { registerEve } from "@propermotion/virgo-observe/eve";
export const virgo = registerEve({
projectName: "support-agent",
captureContent: true,
// cwd: repositoryRoot, // when the process starts outside the project
});
export default virgo.instrumentation;virgo.registrationReport() exposes activation, unsupported versions, recording
failures, and delivery failures without credentials or captured content. Eve calls
setup and flush; callers may also use forceFlush() and shutdown().
Eve traces include turn roots, step attempts, model calls, and dispatched actions.
One session's turns share a trace ID; subagent turns attach to their dispatching
action. Tool events are recorded once through action.*. Model messages, system
instructions, tool values, token usage, errors, session identity, and upstream
trace links are retained. The adapter uses Eve's durable JSON state and stable
operation IDs, so a replacement worker can finish the same span. No live span or
process-local parent must survive suspension. Replayed completions retain the same
span ID; Virgo merges repeated delivery. A missing start is reported and omitted.
Incomplete model streams without a terminal event do not produce a model span;
their enclosing step still records its terminal outcome.
Eve's environment is the default unless explicitly overridden. Unsupported Eve
versions disable this adapter with an actionable registration report. The adapter
owns a private OTLP delivery boundary and leaves the global OpenTelemetry provider
alone. Use spanExporter for custom delivery; Eve does not accept tracerProvider
because its spans must retain durable framework identities across workers.
Pi
Install the extension from a Pi project:
pi install -l npm:@propermotion/[email protected]Run Pi normally after installation:
pi -p "Print the word telemetry and nothing else."The extension emits one trace per Pi agent loop:
pi.agentas the agent root;- one LLM child for each turn, with
gen_ai.system_instructionsand a snapshot ofgen_ai.input.messagestaken at that turn's context hook; and - one tool child for each tool execution.
The spans use standard OpenTelemetry plus gen_ai.* and OpenInference role
attributes already normalized by Virgo. Short-lived print-mode runs flush at
agent_end; session shutdown flushes and closes the package-owned provider.
Exporter failures never change Pi behavior.
Context snapshots remain paired with their model turns when Pi queues lifecycle
callbacks behind later model requests. The system instructions reflect the active
prompt after before_agent_start extensions have run. Both fields follow the same
content-capture and Observe-key redaction policy as prompts and tool values.
Full content is enabled by default to match the Observe onboarding selection.
Set VIRGO_CAPTURE_CONTENT=false before starting Pi for metadata-only export.
The Observe key itself is always redacted from captured values. Do not place
other credentials in prompts or tool values.
Useful optional configuration:
export VIRGO_PROJECT_NAME=my-agent
export OTEL_SERVICE_NAME=pi-worker
export VIRGO_ENVIRONMENT=production
export VIRGO_RELEASE=release-7
export VIRGO_ENDPOINT=https://api.propermotion.ai/v1/lab-ingest/otelEnvironment variables are optional when the application already knows its deployment. Pass that value or its existing OpenTelemetry resource:
registerPi({ environment: settings.environment });
// Or reuse the same resource used to configure your application's provider:
registerPi({ resource: applicationResource });Both adapters resolve the first configured label in this order:
VIRGO_ENVIRONMENToverride.- Explicit
environmentoption from application configuration. - The supplied
resourceoption. - Eve's runtime environment, when using Eve.
OTEL_RESOURCE_ATTRIBUTES.APP_ENV,VERCEL_TARGET_ENV, thenVERCEL_ENV.NODE_ENVonly when it isdevelopmentortest.unspecifiedwhen no deployment label is available.
Resource lookup prefers deployment.environment.name, then
deployment.environment, then platform.environment. Labels preserve case and
custom stage names; values in OTEL_RESOURCE_ATTRIBUTES are percent-decoded.
Blank variables fall through; the selected label must contain 1–80 Unicode
characters without control/non-printable characters. An invalid override fails
validation instead of silently using a lower-priority label.
NODE_ENV=production is build mode and cannot distinguish staging from production.
CI flags, cloud host markers, and the hosted Virgo endpoint do not identify the
deployment.
Set one override before starting the process, even when the adapter already has
an explicit environment option:
export VIRGO_ENVIRONMENT=local
# Or VIRGO_ENVIRONMENT=prod for production, or VIRGO_ENVIRONMENT=evals for evaluation runs.The label is resolved once when the adapter initializes. local, prod, and
evals stay exactly as supplied; custom labels remain valid. Evaluation runners
can also pass environment: "evals"; CI or NODE_ENV=test alone does not imply
an evaluation run. prod and production remain distinct scopes, so keep your
existing label when upgrading.
Upgrading: Pi deployments that used the old implicit production default must supply a production label to retain that scope. Existing traces are not relabeled. The Traces environment filter separates deployments within one workspace; Columns → Environment optionally displays the label.
Applications embedding Pi can create a project extension and inspect its bounded registration report:
import { registerPi } from "@propermotion/virgo-observe/pi";
export const virgo = registerPi({ projectName: "support-agent" });
export default virgo.extension;
console.log(virgo.registrationReport());
await virgo.forceFlush();
await virgo.shutdown();When the existing resource loader takes inline extensions, add virgo.extension
to its extensionFactories and retain the other factories. A dependency install
alone does not activate an embedded loader. Run forceFlush() and shutdown()
only at the application's existing lifecycle boundaries.
registrationReport().certifiedFrameworks lists both certified package/version
pairs; it does not detect the installed host version. The legacy
certifiedFrameworkVersion field remains 0.73.1 for existing consumers.
The package never replaces the global OpenTelemetry provider. An embedded
application that owns a provider can pass it as tracerProvider; Virgo uses it
without shutting it down. Do not install another Pi tracing extension on the
same lifecycle because that creates duplicate model and tool spans.
Both integrations cover Agent traces. System, Product, and Metrics are not yet
implemented by these adapters. The Python virgo-observe package
remains the full register/trace/feedback/metric SDK.
Both adapters preserve standard OTEL_RESOURCE_ATTRIBUTES, including
vcs.ref.head.revision for the exact commit SHA. Set it in the application's
runtime environment, alongside VIRGO_RELEASE for its release identity.
Observe's configured service, environment, and release take precedence over
resource attributes with the same names. An externally supplied tracer provider
continues to own its resources. The public OTel TracerProvider interface does
not expose its resource: when passing tracerProvider, also pass the same
resource to reuse its environment. Virgo does not inspect private SDK fields
or modify the provider's spans/resources. For export through an Observe key,
configure that external provider resource with the resolved
deployment.environment.name and
platform.observe.environment_contract=observe-runtime-environment-v1 so the
receiver preserves its environment. Virgo-owned exporters attach both automatically.
Full content defaults to enabled for both adapters. VIRGO_CAPTURE_CONTENT=false
or captureContent: false omits it, including content saved by an earlier Eve
worker when a resumed worker has a stricter policy. This is an explicit capture
choice, including Eve channels whose audience is unknown. The Observe key is
redacted; other credentials must not be included in agent content.
Development
pnpm --filter @propermotion/virgo-observe format
pnpm --filter @propermotion/virgo-observe lint
pnpm --filter @propermotion/virgo-observe typecheck
pnpm --filter @propermotion/virgo-observe test
pnpm --filter @propermotion/virgo-observe test:e2e
pnpm --filter @propermotion/virgo-observe buildNew framework adapters should reuse config.ts and runtime.ts, add one public
subpath and an optional exact framework peer, then verify lifecycle, privacy,
delivery failure, and real-runtime behavior. The root/Pi entrypoints do not import
Eve, so a Pi installation does not require Eve or its newer Node runtime.
Release and first publication
Publish a GitHub release whose tag exactly matches
virgo-observe-npm-v<package version>. The tag-bound
.github/workflows/release-virgo-observe-npm.yml workflow reruns lint,
typecheck, and tests before publishing through npm trusted publishing.
Prereleases use the beta npm tag; stable versions use latest. The first publish
requires an npm account authorized for the @propermotion scope. Authenticate
with npm login and publish the verified package, or supply NPM_TOKEN to the
release workflow. npm may require browser/2FA authorization for that first publish.
After the package exists, configure npm trusted publishing for GitHub repository
rafitj/platform, workflow release-virgo-observe-npm.yml. Subsequent releases
use OIDC and need no long-lived npm token.
Before release, run the checks above, pack the package, and verify the installed
tarball in real Pi and Eve runtimes. After publication, install @0.3.0 from npm
in a fresh project and repeat the agent/model/tool trace check against Virgo.
Deploy the matching backend Observe setup recipe to expose Eve in onboarding;
deploy the receiver correction in this release as well, so reordered Eve batches
keep the user prompt instead of substituting tool arguments.
