@raindrop-ai/pi-agent 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,6 +39,19 @@ pi install npm:@raindrop-ai/pi-agent
39
39
 
40
40
  Set `RAINDROP_WRITE_KEY` in your environment. Traces appear automatically.
41
41
 
42
+ ## Projects
43
+
44
+ If your org has multiple projects, route events to a specific one by passing its slug as `projectId` programmatically:
45
+
46
+ ```typescript
47
+ const raindrop = createRaindropPiAgent({
48
+ writeKey: "your-write-key",
49
+ projectId: "support-prod",
50
+ });
51
+ ```
52
+
53
+ For the CLI extension, set the slug via the `RAINDROP_PROJECT_ID` env var (or the `project_id` config-file key). Either way this sets the `X-Raindrop-Project-Id` header on every event. Omit it (or use `"default"`) to use your org's default **Production** project — the existing behavior. Single-project orgs need nothing new.
54
+
42
55
  ## Payload size limits
43
56
 
44
57
  Event input/output are capped at **1,000,000 characters per field** (span
@@ -1,4 +1,4 @@
1
- // ../core/dist/chunk-SK6EJEO7.js
1
+ // ../core/dist/chunk-WKRW55KX.js
2
2
  function getCrypto() {
3
3
  const c = globalThis.crypto;
4
4
  return c;
@@ -56,6 +56,20 @@ function base64Encode(bytes) {
56
56
  function generateId() {
57
57
  return base64Encode(randomBytes(12)).replace(/[+/=]/g, "").slice(0, 16);
58
58
  }
59
+ function runWithTracingSuppressed(fn) {
60
+ const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
61
+ if (typeof hook !== "function") return fn();
62
+ let started = false;
63
+ try {
64
+ return hook(() => {
65
+ started = true;
66
+ return fn();
67
+ });
68
+ } catch (err) {
69
+ if (started) throw err;
70
+ return fn();
71
+ }
72
+ }
59
73
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
60
74
  var MAX_RETRY_DELAY_MS = 3e4;
61
75
  function wait(ms) {
@@ -166,15 +180,17 @@ async function postJson(url, body, headers, opts) {
166
180
  const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
167
181
  await withRetry(
168
182
  async () => {
169
- const resp = await fetch(url, {
170
- method: "POST",
171
- headers: {
172
- "Content-Type": "application/json",
173
- ...headers
174
- },
175
- body: JSON.stringify(body),
176
- signal: AbortSignal.timeout(timeoutMs)
177
- });
183
+ const resp = await runWithTracingSuppressed(
184
+ () => fetch(url, {
185
+ method: "POST",
186
+ headers: {
187
+ "Content-Type": "application/json",
188
+ ...headers
189
+ },
190
+ body: JSON.stringify(body),
191
+ signal: AbortSignal.timeout(timeoutMs)
192
+ })
193
+ );
178
194
  if (!resp.ok) {
179
195
  const text = await resp.text().catch(() => "");
180
196
  const err = new Error(
@@ -1122,11 +1138,36 @@ var TraceShipper = class {
1122
1138
  // ../core/dist/index.node.js
1123
1139
  import { AsyncLocalStorage } from "async_hooks";
1124
1140
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
1141
+ var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1142
+ "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
1143
+ );
1144
+ function findOtelContextManager() {
1145
+ var _a;
1146
+ for (const sym of Object.getOwnPropertySymbols(globalThis)) {
1147
+ if (!((_a = sym.description) == null ? void 0 : _a.startsWith("opentelemetry.js.api."))) continue;
1148
+ const api = globalThis[sym];
1149
+ const cm = api == null ? void 0 : api.context;
1150
+ if (cm && typeof cm.with === "function" && typeof cm.active === "function") {
1151
+ return cm;
1152
+ }
1153
+ }
1154
+ return void 0;
1155
+ }
1156
+ function installTracingSuppressionHook() {
1157
+ if (typeof globalThis.RAINDROP_SUPPRESS_TRACING === "function") return;
1158
+ const hook = (fn) => {
1159
+ const cm = findOtelContextManager();
1160
+ if (!cm) return fn();
1161
+ return cm.with(cm.active().setValue(SUPPRESS_TRACING_KEY, true), fn);
1162
+ };
1163
+ globalThis.RAINDROP_SUPPRESS_TRACING = hook;
1164
+ }
1165
+ installTracingSuppressionHook();
1125
1166
 
1126
1167
  // package.json
1127
1168
  var package_default = {
1128
1169
  name: "@raindrop-ai/pi-agent",
1129
- version: "0.0.7",
1170
+ version: "0.0.9",
1130
1171
  description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
1131
1172
  type: "module",
1132
1173
  license: "MIT",
@@ -25,7 +25,7 @@ __export(extension_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(extension_exports);
27
27
 
28
- // ../core/dist/chunk-SK6EJEO7.js
28
+ // ../core/dist/chunk-WKRW55KX.js
29
29
  function getCrypto() {
30
30
  const c = globalThis.crypto;
31
31
  return c;
@@ -72,6 +72,20 @@ function base64Encode(bytes) {
72
72
  function generateId() {
73
73
  return base64Encode(randomBytes(12)).replace(/[+/=]/g, "").slice(0, 16);
74
74
  }
75
+ function runWithTracingSuppressed(fn) {
76
+ const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
77
+ if (typeof hook !== "function") return fn();
78
+ let started = false;
79
+ try {
80
+ return hook(() => {
81
+ started = true;
82
+ return fn();
83
+ });
84
+ } catch (err) {
85
+ if (started) throw err;
86
+ return fn();
87
+ }
88
+ }
75
89
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
76
90
  var MAX_RETRY_DELAY_MS = 3e4;
77
91
  function wait(ms) {
@@ -182,15 +196,17 @@ async function postJson(url, body, headers, opts) {
182
196
  const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
183
197
  await withRetry(
184
198
  async () => {
185
- const resp = await fetch(url, {
186
- method: "POST",
187
- headers: {
188
- "Content-Type": "application/json",
189
- ...headers
190
- },
191
- body: JSON.stringify(body),
192
- signal: AbortSignal.timeout(timeoutMs)
193
- });
199
+ const resp = await runWithTracingSuppressed(
200
+ () => fetch(url, {
201
+ method: "POST",
202
+ headers: {
203
+ "Content-Type": "application/json",
204
+ ...headers
205
+ },
206
+ body: JSON.stringify(body),
207
+ signal: AbortSignal.timeout(timeoutMs)
208
+ })
209
+ );
194
210
  if (!resp.ok) {
195
211
  const text = await resp.text().catch(() => "");
196
212
  const err = new Error(
@@ -1138,6 +1154,31 @@ var TraceShipper = class {
1138
1154
  // ../core/dist/index.node.js
1139
1155
  var import_async_hooks = require("async_hooks");
1140
1156
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
1157
+ var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1158
+ "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
1159
+ );
1160
+ function findOtelContextManager() {
1161
+ var _a;
1162
+ for (const sym of Object.getOwnPropertySymbols(globalThis)) {
1163
+ if (!((_a = sym.description) == null ? void 0 : _a.startsWith("opentelemetry.js.api."))) continue;
1164
+ const api = globalThis[sym];
1165
+ const cm = api == null ? void 0 : api.context;
1166
+ if (cm && typeof cm.with === "function" && typeof cm.active === "function") {
1167
+ return cm;
1168
+ }
1169
+ }
1170
+ return void 0;
1171
+ }
1172
+ function installTracingSuppressionHook() {
1173
+ if (typeof globalThis.RAINDROP_SUPPRESS_TRACING === "function") return;
1174
+ const hook = (fn) => {
1175
+ const cm = findOtelContextManager();
1176
+ if (!cm) return fn();
1177
+ return cm.with(cm.active().setValue(SUPPRESS_TRACING_KEY, true), fn);
1178
+ };
1179
+ globalThis.RAINDROP_SUPPRESS_TRACING = hook;
1180
+ }
1181
+ installTracingSuppressionHook();
1141
1182
 
1142
1183
  // src/internal/config.ts
1143
1184
  var import_node_fs = require("fs");
@@ -1197,7 +1238,7 @@ function resolveLocalWorkshopUrl(fileValue) {
1197
1238
  // package.json
1198
1239
  var package_default = {
1199
1240
  name: "@raindrop-ai/pi-agent",
1200
- version: "0.0.7",
1241
+ version: "0.0.9",
1201
1242
  description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
1202
1243
  type: "module",
1203
1244
  license: "MIT",
@@ -1,5 +1,5 @@
1
1
  import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
2
- import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-D0J2tEXx.cjs';
2
+ import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-CSO1bDLs.cjs';
3
3
 
4
4
  interface EventMetadata {
5
5
  userId?: string;
@@ -1,5 +1,5 @@
1
1
  import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
2
- import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-D0J2tEXx.js';
2
+ import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-CSO1bDLs.js';
3
3
 
4
4
  interface EventMetadata {
5
5
  userId?: string;
package/dist/extension.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  resolveLocalDebuggerBaseUrl,
15
15
  safeStringify,
16
16
  truncate
17
- } from "./chunk-GILK5ZDM.js";
17
+ } from "./chunk-TEXLELWC.js";
18
18
 
19
19
  // src/internal/config.ts
20
20
  import { existsSync, readFileSync } from "fs";
package/dist/index.cjs CHANGED
@@ -24,7 +24,7 @@ __export(index_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(index_exports);
26
26
 
27
- // ../core/dist/chunk-SK6EJEO7.js
27
+ // ../core/dist/chunk-WKRW55KX.js
28
28
  function getCrypto() {
29
29
  const c = globalThis.crypto;
30
30
  return c;
@@ -79,6 +79,20 @@ function base64Encode(bytes) {
79
79
  }
80
80
  return out;
81
81
  }
82
+ function runWithTracingSuppressed(fn) {
83
+ const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
84
+ if (typeof hook !== "function") return fn();
85
+ let started = false;
86
+ try {
87
+ return hook(() => {
88
+ started = true;
89
+ return fn();
90
+ });
91
+ } catch (err) {
92
+ if (started) throw err;
93
+ return fn();
94
+ }
95
+ }
82
96
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
83
97
  var MAX_RETRY_DELAY_MS = 3e4;
84
98
  function wait(ms) {
@@ -189,15 +203,17 @@ async function postJson(url, body, headers, opts) {
189
203
  const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
190
204
  await withRetry(
191
205
  async () => {
192
- const resp = await fetch(url, {
193
- method: "POST",
194
- headers: {
195
- "Content-Type": "application/json",
196
- ...headers
197
- },
198
- body: JSON.stringify(body),
199
- signal: AbortSignal.timeout(timeoutMs)
200
- });
206
+ const resp = await runWithTracingSuppressed(
207
+ () => fetch(url, {
208
+ method: "POST",
209
+ headers: {
210
+ "Content-Type": "application/json",
211
+ ...headers
212
+ },
213
+ body: JSON.stringify(body),
214
+ signal: AbortSignal.timeout(timeoutMs)
215
+ })
216
+ );
201
217
  if (!resp.ok) {
202
218
  const text = await resp.text().catch(() => "");
203
219
  const err = new Error(
@@ -1145,11 +1161,36 @@ var TraceShipper = class {
1145
1161
  // ../core/dist/index.node.js
1146
1162
  var import_async_hooks = require("async_hooks");
1147
1163
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
1164
+ var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1165
+ "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
1166
+ );
1167
+ function findOtelContextManager() {
1168
+ var _a;
1169
+ for (const sym of Object.getOwnPropertySymbols(globalThis)) {
1170
+ if (!((_a = sym.description) == null ? void 0 : _a.startsWith("opentelemetry.js.api."))) continue;
1171
+ const api = globalThis[sym];
1172
+ const cm = api == null ? void 0 : api.context;
1173
+ if (cm && typeof cm.with === "function" && typeof cm.active === "function") {
1174
+ return cm;
1175
+ }
1176
+ }
1177
+ return void 0;
1178
+ }
1179
+ function installTracingSuppressionHook() {
1180
+ if (typeof globalThis.RAINDROP_SUPPRESS_TRACING === "function") return;
1181
+ const hook = (fn) => {
1182
+ const cm = findOtelContextManager();
1183
+ if (!cm) return fn();
1184
+ return cm.with(cm.active().setValue(SUPPRESS_TRACING_KEY, true), fn);
1185
+ };
1186
+ globalThis.RAINDROP_SUPPRESS_TRACING = hook;
1187
+ }
1188
+ installTracingSuppressionHook();
1148
1189
 
1149
1190
  // package.json
1150
1191
  var package_default = {
1151
1192
  name: "@raindrop-ai/pi-agent",
1152
- version: "0.0.7",
1193
+ version: "0.0.9",
1153
1194
  description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
1154
1195
  type: "module",
1155
1196
  license: "MIT",
@@ -357,6 +357,42 @@ declare class TraceShipper {
357
357
  shutdown(): Promise<void>;
358
358
  }
359
359
 
360
+ /**
361
+ * Run telemetry egress with OpenTelemetry tracing suppressed.
362
+ *
363
+ * Why this exists
364
+ * ---------------
365
+ * Raindrop integrations ship spans/events over HTTP with the global `fetch`
366
+ * (see {@link ../http.ts `postJson`}). When the host app also runs an OTel
367
+ * fetch/undici instrumentation — e.g. `@vercel/otel`'s `registerOTel`, which
368
+ * every Eve agent installs — that instrumentation wraps *our own* telemetry
369
+ * POSTs in a `fetch POST <endpoint>` span. Those spans are then handed to the
370
+ * very exporter that issued the request, so they get shipped right back to
371
+ * Raindrop and Workshop as standalone "runs" (and, because each export issues
372
+ * another fetch, they feed back on themselves). The result is a run list
373
+ * flooded with `fetch POST .../v1/traces`, `.../events/track_partial` and
374
+ * `.../live` entries that drown out the real agent turns — especially with
375
+ * sub-agents, where every sandbox runs its own instrumentation.
376
+ *
377
+ * The OTel-blessed fix is to mark the active context as "tracing suppressed"
378
+ * around the request; instrumentations check `isTracingSuppressed` and return
379
+ * a no-op span instead of recording one. We do this through a hook stashed on
380
+ * `globalThis` by the Node entrypoint ({@link ../index.node.ts}) so that:
381
+ * - `@opentelemetry/api` / `@opentelemetry/core` stay *optional* — core never
382
+ * hard-depends on them, and the hook is simply absent when they (and thus
383
+ * any instrumentation to suppress) are not installed; and
384
+ * - the browser bundle never pulls in `node:module`, mirroring how core
385
+ * injects `AsyncLocalStorage` via `RAINDROP_ASYNC_LOCAL_STORAGE`.
386
+ *
387
+ * When no hook is present the callback runs unchanged, so suppression is a
388
+ * best-effort no-op rather than a hard requirement.
389
+ */
390
+ /** Hook signature: run `fn` with OTel tracing suppressed, returning its value. */
391
+ type SuppressTracingHook = <T>(fn: () => T) => T;
392
+ declare global {
393
+ var RAINDROP_SUPPRESS_TRACING: SuppressTracingHook | undefined;
394
+ }
395
+
360
396
  type ParentSpanContext = {
361
397
  traceIdB64: string;
362
398
  spanIdB64: string;
@@ -357,6 +357,42 @@ declare class TraceShipper {
357
357
  shutdown(): Promise<void>;
358
358
  }
359
359
 
360
+ /**
361
+ * Run telemetry egress with OpenTelemetry tracing suppressed.
362
+ *
363
+ * Why this exists
364
+ * ---------------
365
+ * Raindrop integrations ship spans/events over HTTP with the global `fetch`
366
+ * (see {@link ../http.ts `postJson`}). When the host app also runs an OTel
367
+ * fetch/undici instrumentation — e.g. `@vercel/otel`'s `registerOTel`, which
368
+ * every Eve agent installs — that instrumentation wraps *our own* telemetry
369
+ * POSTs in a `fetch POST <endpoint>` span. Those spans are then handed to the
370
+ * very exporter that issued the request, so they get shipped right back to
371
+ * Raindrop and Workshop as standalone "runs" (and, because each export issues
372
+ * another fetch, they feed back on themselves). The result is a run list
373
+ * flooded with `fetch POST .../v1/traces`, `.../events/track_partial` and
374
+ * `.../live` entries that drown out the real agent turns — especially with
375
+ * sub-agents, where every sandbox runs its own instrumentation.
376
+ *
377
+ * The OTel-blessed fix is to mark the active context as "tracing suppressed"
378
+ * around the request; instrumentations check `isTracingSuppressed` and return
379
+ * a no-op span instead of recording one. We do this through a hook stashed on
380
+ * `globalThis` by the Node entrypoint ({@link ../index.node.ts}) so that:
381
+ * - `@opentelemetry/api` / `@opentelemetry/core` stay *optional* — core never
382
+ * hard-depends on them, and the hook is simply absent when they (and thus
383
+ * any instrumentation to suppress) are not installed; and
384
+ * - the browser bundle never pulls in `node:module`, mirroring how core
385
+ * injects `AsyncLocalStorage` via `RAINDROP_ASYNC_LOCAL_STORAGE`.
386
+ *
387
+ * When no hook is present the callback runs unchanged, so suppression is a
388
+ * best-effort no-op rather than a hard requirement.
389
+ */
390
+ /** Hook signature: run `fn` with OTel tracing suppressed, returning its value. */
391
+ type SuppressTracingHook = <T>(fn: () => T) => T;
392
+ declare global {
393
+ var RAINDROP_SUPPRESS_TRACING: SuppressTracingHook | undefined;
394
+ }
395
+
360
396
  type ParentSpanContext = {
361
397
  traceIdB64: string;
362
398
  spanIdB64: string;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Agent } from '@earendil-works/pi-agent-core';
2
- import { A as Attachment } from './index.d-D0J2tEXx.cjs';
2
+ import { A as Attachment } from './index.d-CSO1bDLs.cjs';
3
3
 
4
4
  /**
5
5
  * Options for the Raindrop Pi Agent client.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Agent } from '@earendil-works/pi-agent-core';
2
- import { A as Attachment } from './index.d-D0J2tEXx.js';
2
+ import { A as Attachment } from './index.d-CSO1bDLs.js';
3
3
 
4
4
  /**
5
5
  * Options for the Raindrop Pi Agent client.
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  resolveLocalDebuggerBaseUrl,
18
18
  safeStringify,
19
19
  truncate
20
- } from "./chunk-GILK5ZDM.js";
20
+ } from "./chunk-TEXLELWC.js";
21
21
 
22
22
  // src/internal/subscriber.ts
23
23
  function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, options, debug) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raindrop-ai/pi-agent",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Raindrop observability for Pi Agent — automatic tracing via subscriber or pi-coding-agent extension",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -54,7 +54,7 @@
54
54
  "tsup": "^8.5.1",
55
55
  "typescript": "^5.7.3",
56
56
  "vitest": "^2.1.9",
57
- "@raindrop-ai/core": "0.0.4"
57
+ "@raindrop-ai/core": "0.0.5"
58
58
  },
59
59
  "tsup": {
60
60
  "entry": [