@raindrop-ai/ash
v0.0.2
Published
Raindrop integration for Vercel's Ash agent framework (OTel traces to Raindrop + Workshop)
Downloads
111
Keywords
Readme
@raindrop-ai/ash
Raindrop integration for Vercel's Ash agent framework.
Drops into agent/instrumentation.ts and ships your Ash agent's OpenTelemetry
traces to:
- Raindrop (
https://api.raindrop.ai/v1/tracesby default), and - the local Workshop daemon (
http://localhost:5899) — when one is reachable.
Both destinations receive the same OTLP/HTTP JSON payload, so an agent that
works in production also works in raindrop workshop without changing any code.
Install
pnpm add @raindrop-ai/ash @vercel/otel @opentelemetry/api @opentelemetry/sdk-trace-baseexperimental-ash is expected to already be in your agent project. Cross-sandbox
sub-agent detection requires experimental-ash@>=0.23.0; older versions still get
session-level telemetry, sub-agents just won't carry parent linkage.
Usage
// agent/instrumentation.ts
import { registerOTel } from "@vercel/otel";
import { defineRaindropInstrumentation } from "@raindrop-ai/ash";
export default defineRaindropInstrumentation({
registerOTel,
writeKey: process.env.RAINDROP_WRITE_KEY,
});That's it. The framework auto-discovers agent/instrumentation.ts and runs it
at server startup before any agent code. Pass registerOTel from @vercel/otel
so Ash's own OTel spans (workflow/step/fetch) are exported — without it the
integration still wires up Raindrop's AI SDK telemetry but skips the underlying
OTel registration.
Configuration
defineRaindropInstrumentation({
registerOTel, // from @vercel/otel
writeKey: process.env.RAINDROP_WRITE_KEY,
endpoint: "https://api.raindrop.ai/v1/", // default
localWorkshopUrl: undefined, // env + auto-detect by default
serviceName: "support-agent", // defaults to the Ash agent name
metadata: { team: "support", tier: "prod" },
recordInputs: true, // forwarded to Ash
recordOutputs: true, // forwarded to Ash
debug: false, // or RAINDROP_AI_DEBUG=1
});Identifying users
Pass raindrop.userId (and optionally raindrop.convoId) on the metadata map
and they will be attached to every event from this Ash session:
defineRaindropInstrumentation({
registerOTel,
writeKey: process.env.RAINDROP_WRITE_KEY,
metadata: {
"raindrop.userId": "user_123",
"raindrop.convoId": "convo_456",
team: "support",
},
});For dynamic per-turn identification (e.g. derived from the authenticated
request), set the keys on the Ash session's runtime context instead — the
integration reads ash.session.id, raindrop.userId, and raindrop.convoId
from the active session at event time.
Workshop / production mirroring
localWorkshopUrl controls Workshop mirroring:
| Value | Behavior |
| -------------- | --------------------------------------------------------------------- |
| string | Force-enable; mirror every export to that URL. |
| false | Opt out entirely (skip env vars and auto-detect). |
| undefined | Honor RAINDROP_WORKSHOP / RAINDROP_LOCAL_DEBUGGER, then auto-detect localhost during development. |
Run raindrop workshop locally to get a daemon at http://localhost:5899 —
the integration will start mirroring as soon as the daemon is reachable.
Production-only mode
defineRaindropInstrumentation({
registerOTel,
writeKey: process.env.RAINDROP_WRITE_KEY,
localWorkshopUrl: false,
});Workshop-only mode (no Raindrop account)
Leave writeKey undefined. Spans still flow to Workshop:
defineRaindropInstrumentation({
registerOTel,
localWorkshopUrl: "http://localhost:5899/v1/",
});Sub-agents
Ash runs each sub-agent in its own V8 sandbox. The integration uses
experimental-ash's first-class getSession() API (added in
[email protected]) to detect when the current sandbox was dispatched
as a sub-agent and lifts the parent's turn identity onto every sub-agent event:
| Attribute | Description |
| ------------------------------- | ------------------------------------------------------------------------------------------ |
| raindrop.agent.role | "subagent" when the current sandbox is a sub-agent dispatched by another agent; "root" otherwise. |
| raindrop.subagent.name | The sub-agent's agentName (e.g. weatherResearcher). |
| raindrop.parent.sessionId | The parent agent's Ash session id. |
| raindrop.parent.turnId | The parent's turn id that dispatched this sub-agent. |
| raindrop.parent.turnSequence | The parent's turn sequence number. |
These power the AGENT block in Workshop's Overview tab and let the Raindrop dashboard stitch sub-agent events under the parent turn that dispatched them.
If you're running experimental-ash < 0.23.0, sub-agent events still ship —
they just won't carry parent lineage and will appear as root events in the feed.
What gets traced
Ash automatically creates rich trace hierarchies per turn:
ash.turn // session/turn metadata
+-- ai.streamText // step
| +-- ai.streamText.doStream // model call
| +-- ai.toolCall { toolName: search } // tool exec
+-- ai.streamTextThese flow through Raindrop's standard ingestion and show up in both the Raindrop UI and Workshop with full nesting + AI SDK attributes.
Notes
- This package depends on
@raindrop-ai/corefor OTLP serialization and the Workshop mirroring helper. - The exporter implements the
SpanExporterinterface structurally, so it works against both@opentelemetry/sdk-trace-base1.x and 2.x.
Examples
examples/ash-basic— single-agent example with one tool (get_weather) and an end-to-end dashboard verifier.examples/ash-subagents— parent agent dispatchingweatherResearcher+attractionsFindersub-agents, verifying cross-sandbox nesting against the production dashboard.
