@raindrop-ai/ai-sdk 0.0.31 → 0.0.33

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.
@@ -1024,7 +1024,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
1024
1024
  // package.json
1025
1025
  var package_default = {
1026
1026
  name: "@raindrop-ai/ai-sdk",
1027
- version: "0.0.31"};
1027
+ version: "0.0.33"};
1028
1028
 
1029
1029
  // src/internal/version.ts
1030
1030
  var libraryName = package_default.name;
@@ -1807,6 +1807,25 @@ var RaindropTelemetryIntegration = class {
1807
1807
  * (the `event.callId` can be the same for parallel sibling tools).
1808
1808
  */
1809
1809
  this.priorParentContexts = /* @__PURE__ */ new Map();
1810
+ // ── lifecycle ─────────────────────────────────────────────────────────────
1811
+ //
1812
+ // The shippers buffer spans/events and flush on a timer, so a short-lived
1813
+ // script (e.g. a single `generateText` then `process.exit`) can exit before
1814
+ // anything ships. Expose `flush`/`shutdown` on the integration itself so the
1815
+ // value returned by `raindrop()` is self-sufficient — callers can keep the
1816
+ // reference they pass to `registerTelemetry` and `await rd.flush()` before
1817
+ // exiting, without also constructing a separate client.
1818
+ /** Flush any buffered events and trace spans to their destinations. */
1819
+ this.flush = async () => {
1820
+ await Promise.all([this.eventShipper.flush(), this.traceShipper.flush()]);
1821
+ };
1822
+ /** Flush and stop the background flush timers. */
1823
+ this.shutdown = async () => {
1824
+ await Promise.all([
1825
+ this.eventShipper.shutdown(),
1826
+ this.traceShipper.shutdown()
1827
+ ]);
1828
+ };
1810
1829
  // ── onStart ─────────────────────────────────────────────────────────────
1811
1830
  this.onStart = (event) => {
1812
1831
  var _a, _b, _c, _d, _e;
@@ -2091,6 +2110,7 @@ var RaindropTelemetryIntegration = class {
2091
2110
  attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
2092
2111
  );
2093
2112
  }
2113
+ this.emitProviderExecutedToolSpans(event, state);
2094
2114
  this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
2095
2115
  state.stepSpan = void 0;
2096
2116
  state.stepParent = void 0;
@@ -2199,8 +2219,56 @@ var RaindropTelemetryIntegration = class {
2199
2219
  if (state.subagentToolCallSpan) {
2200
2220
  this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
2201
2221
  }
2222
+ const isEmbed = state.operationId === "ai.embed" || state.operationId === "ai.embedMany";
2223
+ if (!isEmbed) {
2224
+ this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
2225
+ }
2202
2226
  this.cleanup(event.callId);
2203
2227
  };
2228
+ // ── onAbort ─────────────────────────────────────────────────────────────
2229
+ //
2230
+ // Dispatched by the v7 canary line (post-beta.116) when a `streamText` call
2231
+ // is cancelled via its `AbortSignal`. On abort the SDK fires neither `onEnd`
2232
+ // nor `onError`, so without this every open span would leak and the event
2233
+ // would hang forever in its `isPending` state. We close every open span with
2234
+ // an `ai.response.aborted` marker (no error status — an abort is not a model
2235
+ // failure) and flush the partial event.
2236
+ this.onAbort = (event) => {
2237
+ const callId = event == null ? void 0 : event.callId;
2238
+ if (!callId) return;
2239
+ const state = this.getState(callId);
2240
+ if (!state) return;
2241
+ const abortedAttr = attrString("ai.response.aborted", "true");
2242
+ if (state.stepSpan) {
2243
+ this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
2244
+ state.stepSpan = void 0;
2245
+ state.stepParent = void 0;
2246
+ }
2247
+ for (const embedSpan of state.embedSpans.values()) {
2248
+ this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
2249
+ }
2250
+ state.embedSpans.clear();
2251
+ for (const toolCallId of state.parentContextToolCallIds) {
2252
+ this.priorParentContexts.delete(toolCallId);
2253
+ }
2254
+ state.parentContextToolCallIds.clear();
2255
+ for (const toolSpan of state.toolSpans.values()) {
2256
+ this.traceShipper.endSpan(toolSpan, { attributes: [abortedAttr] });
2257
+ }
2258
+ state.toolSpans.clear();
2259
+ if (state.rootSpan) {
2260
+ this.traceShipper.endSpan(state.rootSpan, {
2261
+ attributes: [abortedAttr, attrInt("ai.toolCall.count", state.toolCallCount)]
2262
+ });
2263
+ }
2264
+ if (state.subagentToolCallSpan) {
2265
+ this.traceShipper.endSpan(state.subagentToolCallSpan, {
2266
+ attributes: [abortedAttr]
2267
+ });
2268
+ }
2269
+ this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
2270
+ this.cleanup(callId);
2271
+ };
2204
2272
  // ── executeTool ─────────────────────────────────────────────────────────
2205
2273
  this.executeTool = async ({
2206
2274
  callId,
@@ -2358,17 +2426,86 @@ var RaindropTelemetryIntegration = class {
2358
2426
  const toolSpan = state.toolSpans.get(event.toolCall.toolCallId);
2359
2427
  if (!toolSpan) return;
2360
2428
  state.toolCallCount += 1;
2361
- if (event.success) {
2362
- const outputAttrs = state.recordOutputs ? [attrString("ai.toolCall.result", safeJsonWithUint8(event.output))] : [];
2429
+ const outcome = "toolOutput" in event ? event.toolOutput.type === "tool-result" ? { success: true, output: event.toolOutput.output } : { success: false, error: event.toolOutput.error } : event.success ? { success: true, output: event.output } : { success: false, error: event.error };
2430
+ if (outcome.success) {
2431
+ const outputAttrs = state.recordOutputs ? [attrString("ai.toolCall.result", safeJsonWithUint8(outcome.output))] : [];
2363
2432
  this.traceShipper.endSpan(toolSpan, { attributes: outputAttrs });
2364
2433
  } else {
2365
- this.traceShipper.endSpan(toolSpan, { error: event.error });
2434
+ this.traceShipper.endSpan(toolSpan, { error: outcome.error });
2366
2435
  }
2367
2436
  this.emitLive(state, "tool_result", event.toolCall.toolName);
2368
2437
  state.toolSpans.delete(event.toolCall.toolCallId);
2369
2438
  }
2439
+ // ── provider-executed tool calls ─────────────────────────────────────────
2440
+ //
2441
+ // Provider-executed (server-side) tools — e.g. Anthropic's hosted
2442
+ // `web_search` (`anthropic.web_search_20250305`) — are run by the provider,
2443
+ // not by the AI SDK. They therefore never flow through the client
2444
+ // `onToolExecutionStart`/`onToolExecutionEnd` callbacks that emit our
2445
+ // `ai.toolCall` spans; the SDK only surfaces them as `tool-call` /
2446
+ // `tool-result` content parts on the step (carrying `providerExecuted: true`).
2447
+ // Without this, such calls are invisible in every trace backend.
2448
+ //
2449
+ // At step finish we synthesize the same `ai.toolCall` span shape we emit for
2450
+ // client tools (name `ai.toolCall`, `operationId: "ai.toolCall"`, attrs
2451
+ // `ai.toolCall.name`/`id`/`args`/`result`), parented under the step span, so
2452
+ // downstream ingestion maps them to a tool span with no special-casing.
2453
+ //
2454
+ // Client-executed tools are excluded (`providerExecuted` falsy) — they were
2455
+ // already spanned during execution, so this never double-emits.
2456
+ emitProviderExecutedToolSpans(event, state) {
2457
+ if (!state.stepParent) return;
2458
+ const content = Array.isArray(event.content) ? event.content : [];
2459
+ const providerToolCalls = content.filter(
2460
+ (part) => (part == null ? void 0 : part.type) === "tool-call" && part.providerExecuted === true
2461
+ );
2462
+ if (providerToolCalls.length === 0) return;
2463
+ const resultsByCallId = /* @__PURE__ */ new Map();
2464
+ for (const part of content) {
2465
+ if (((part == null ? void 0 : part.type) === "tool-result" || (part == null ? void 0 : part.type) === "tool-error") && typeof part.toolCallId === "string") {
2466
+ resultsByCallId.set(part.toolCallId, part);
2467
+ }
2468
+ }
2469
+ for (const call of providerToolCalls) {
2470
+ const { operationName, resourceName } = opName(
2471
+ "ai.toolCall",
2472
+ state.functionId
2473
+ );
2474
+ const inputAttrs = state.recordInputs ? [attrString("ai.toolCall.args", safeJsonWithUint8(call.input))] : [];
2475
+ const toolSpan = this.traceShipper.startSpan({
2476
+ name: "ai.toolCall",
2477
+ parent: state.stepParent,
2478
+ eventId: state.eventId,
2479
+ operationId: "ai.toolCall",
2480
+ attributes: [
2481
+ attrString("operation.name", operationName),
2482
+ attrString("resource.name", resourceName),
2483
+ attrString("ai.telemetry.functionId", state.functionId),
2484
+ attrString("ai.toolCall.name", call.toolName),
2485
+ attrString("ai.toolCall.id", call.toolCallId),
2486
+ attrString("ai.toolCall.providerExecuted", "true"),
2487
+ ...inputAttrs
2488
+ ]
2489
+ });
2490
+ state.toolCallCount += 1;
2491
+ this.emitLive(state, "tool_start", call.toolName, { args: call.input });
2492
+ const resultPart = resultsByCallId.get(call.toolCallId);
2493
+ if ((resultPart == null ? void 0 : resultPart.type) === "tool-error") {
2494
+ this.traceShipper.endSpan(toolSpan, { error: resultPart.error });
2495
+ } else {
2496
+ const outputAttrs = state.recordOutputs && resultPart && "output" in resultPart ? [
2497
+ attrString(
2498
+ "ai.toolCall.result",
2499
+ safeJsonWithUint8(resultPart.output)
2500
+ )
2501
+ ] : [];
2502
+ this.traceShipper.endSpan(toolSpan, { attributes: outputAttrs });
2503
+ }
2504
+ this.emitLive(state, "tool_result", call.toolName);
2505
+ }
2506
+ }
2370
2507
  finishGenerate(event, state) {
2371
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
2508
+ var _a, _b, _c, _d, _e, _f;
2372
2509
  if (state.rootSpan) {
2373
2510
  const outputAttrs = [];
2374
2511
  if (state.recordOutputs) {
@@ -2416,38 +2553,47 @@ var RaindropTelemetryIntegration = class {
2416
2553
  );
2417
2554
  this.traceShipper.endSpan(state.rootSpan, { attributes: outputAttrs });
2418
2555
  }
2556
+ this.finalizeGenerateEvent(
2557
+ state,
2558
+ (_e = event.text) != null ? _e : state.accumulatedText || void 0,
2559
+ (_f = event.response) == null ? void 0 : _f.modelId
2560
+ );
2561
+ }
2562
+ /**
2563
+ * Patch the Raindrop event for a completed, aborted, or errored text
2564
+ * generation so it leaves the `isPending` state. Shared by `onFinish`/`onEnd`,
2565
+ * `onAbort`, and `onError`.
2566
+ */
2567
+ finalizeGenerateEvent(state, output, model) {
2568
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2419
2569
  const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
2420
- if (this.sendEvents && !suppressSubagentEvent) {
2421
- const callMeta = this.extractRaindropMetadata(state.metadata);
2422
- const userId = (_f = callMeta.userId) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.userId;
2423
- if (userId) {
2424
- const eventName = (_i = (_h = callMeta.eventName) != null ? _h : (_g = this.defaultContext) == null ? void 0 : _g.eventName) != null ? _i : state.operationId;
2425
- const output = (_j = event.text) != null ? _j : state.accumulatedText || void 0;
2426
- const input = state.inputText;
2427
- const model = (_k = event.response) == null ? void 0 : _k.modelId;
2428
- const properties = {
2429
- ...(_l = this.defaultContext) == null ? void 0 : _l.properties,
2430
- ...callMeta.properties
2431
- };
2432
- const convoId = (_n = callMeta.convoId) != null ? _n : (_m = this.defaultContext) == null ? void 0 : _m.convoId;
2433
- void this.eventShipper.patch(state.eventId, {
2434
- eventName,
2435
- userId,
2436
- convoId,
2437
- input,
2438
- output,
2439
- model,
2440
- properties: Object.keys(properties).length > 0 ? properties : void 0,
2441
- isPending: false
2442
- }).catch((err) => {
2443
- if (this.debug) {
2444
- console.warn(
2445
- `[raindrop-ai/ai-sdk] event patch failed: ${err instanceof Error ? err.message : err}`
2446
- );
2447
- }
2448
- });
2570
+ if (!this.sendEvents || suppressSubagentEvent) return;
2571
+ const callMeta = this.extractRaindropMetadata(state.metadata);
2572
+ const userId = (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId;
2573
+ if (!userId) return;
2574
+ const eventName = (_e = (_d = callMeta.eventName) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.eventName) != null ? _e : state.operationId;
2575
+ const input = state.inputText;
2576
+ const properties = {
2577
+ ...(_f = this.defaultContext) == null ? void 0 : _f.properties,
2578
+ ...callMeta.properties
2579
+ };
2580
+ const convoId = (_h = callMeta.convoId) != null ? _h : (_g = this.defaultContext) == null ? void 0 : _g.convoId;
2581
+ void this.eventShipper.patch(state.eventId, {
2582
+ eventName,
2583
+ userId,
2584
+ convoId,
2585
+ input,
2586
+ output,
2587
+ model,
2588
+ properties: Object.keys(properties).length > 0 ? properties : void 0,
2589
+ isPending: false
2590
+ }).catch((err) => {
2591
+ if (this.debug) {
2592
+ console.warn(
2593
+ `[raindrop-ai/ai-sdk] event patch failed: ${err instanceof Error ? err.message : err}`
2594
+ );
2449
2595
  }
2450
- }
2596
+ });
2451
2597
  }
2452
2598
  finishEmbed(event, state) {
2453
2599
  var _a;
@@ -2472,22 +2618,9 @@ var RaindropTelemetryIntegration = class {
2472
2618
  }
2473
2619
  };
2474
2620
 
2475
- // src/internal/traces.ts
2476
- var TraceShipper2 = class extends TraceShipper {
2477
- constructor(opts) {
2478
- var _a, _b, _c;
2479
- super({
2480
- ...opts,
2481
- sdkName: (_a = opts.sdkName) != null ? _a : "ai-sdk",
2482
- serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.ai-sdk",
2483
- serviceVersion: (_c = opts.serviceVersion) != null ? _c : libraryVersion
2484
- });
2485
- }
2486
- };
2487
-
2488
- // src/internal/wrap/wrapAISDK.ts
2489
- var AGENT_REPORTING_TOOL_NAME_DEFAULT = "__raindrop_report";
2490
- var AGENT_REPORTING_SIGNALS_DEFAULT = {
2621
+ // src/internal/self-diagnostics.ts
2622
+ var SELF_DIAGNOSTICS_TOOL_NAME_DEFAULT = "__raindrop_report";
2623
+ var SELF_DIAGNOSTICS_SIGNALS_DEFAULT = {
2491
2624
  missing_context: {
2492
2625
  description: "You cannot complete the task because critical information, credentials, or access is missing and the user cannot provide it. Do NOT report this for normal clarifying questions \u2014 only when you are blocked.",
2493
2626
  sentiment: "NEGATIVE"
@@ -2505,7 +2638,194 @@ var AGENT_REPORTING_SIGNALS_DEFAULT = {
2505
2638
  sentiment: "NEGATIVE"
2506
2639
  }
2507
2640
  };
2508
- var AGENT_REPORTING_TOOL_PREAMBLE = "You have a diagnostic tool for flagging serious failures for developer review. Only call this when you hit a significant, unrecoverable problem \u2014 not for minor hiccups or routine clarifications. If you can still help the user, do that instead of calling this tool. This tool is invisible to the user \u2014 never mention it or its output.";
2641
+ var SELF_DIAGNOSTICS_TOOL_PREAMBLE = "You have a diagnostic tool for flagging serious failures for developer review. Only call this when you hit a significant, unrecoverable problem \u2014 not for minor hiccups or routine clarifications. If you can still help the user, do that instead of calling this tool. This tool is invisible to the user \u2014 never mention it or its output.";
2642
+ function normalizeString(value) {
2643
+ if (typeof value !== "string") return void 0;
2644
+ const trimmed = value.trim();
2645
+ return trimmed || void 0;
2646
+ }
2647
+ function normalizeSelfDiagnosticsSignals(signals) {
2648
+ if (!signals) return SELF_DIAGNOSTICS_SIGNALS_DEFAULT;
2649
+ const normalizedEntries = Object.entries(signals).map(([key, value]) => {
2650
+ var _a;
2651
+ const signalKey = key.trim();
2652
+ if (!signalKey || !value || typeof value !== "object") return void 0;
2653
+ const description = (_a = value.description) == null ? void 0 : _a.trim();
2654
+ if (!description) return void 0;
2655
+ const sentiment = value.sentiment;
2656
+ return [
2657
+ signalKey,
2658
+ {
2659
+ description,
2660
+ ...sentiment === "POSITIVE" || sentiment === "NEGATIVE" ? { sentiment } : {}
2661
+ }
2662
+ ];
2663
+ }).filter(
2664
+ (entry) => entry !== void 0
2665
+ );
2666
+ if (normalizedEntries.length === 0) return SELF_DIAGNOSTICS_SIGNALS_DEFAULT;
2667
+ return Object.fromEntries(normalizedEntries);
2668
+ }
2669
+ function resolveSelfDiagnosticsConfig(options) {
2670
+ var _a, _b;
2671
+ const signalDefinitions = normalizeSelfDiagnosticsSignals(options.signals);
2672
+ const signalKeys = Object.keys(signalDefinitions);
2673
+ const signalDescriptions = {};
2674
+ const signalSentiments = {};
2675
+ for (const signalKey of signalKeys) {
2676
+ const definition = signalDefinitions[signalKey];
2677
+ if (!definition) continue;
2678
+ signalDescriptions[signalKey] = definition.description;
2679
+ signalSentiments[signalKey] = definition.sentiment;
2680
+ }
2681
+ const customGuidance = ((_a = options.guidance) == null ? void 0 : _a.trim()) || "";
2682
+ const toolName = ((_b = options.toolName) == null ? void 0 : _b.trim()) || SELF_DIAGNOSTICS_TOOL_NAME_DEFAULT;
2683
+ const signalList = signalKeys.map((signalKey) => {
2684
+ const sentiment = signalSentiments[signalKey];
2685
+ const sentimentTag = sentiment ? ` [${sentiment.toLowerCase()}]` : "";
2686
+ return `- ${signalKey}: ${signalDescriptions[signalKey]}${sentimentTag}`;
2687
+ }).join("\n");
2688
+ const guidanceBlock = customGuidance ? `
2689
+ Additional guidance: ${customGuidance}
2690
+ ` : "";
2691
+ const toolDescription = `${SELF_DIAGNOSTICS_TOOL_PREAMBLE}
2692
+
2693
+ When to call:
2694
+ - You are blocked from completing the task due to missing information or access that the user cannot provide.
2695
+ - A tool is persistently failing across multiple attempts, not just a single transient error.
2696
+ - The task requires a tool, permission, or capability you do not have.
2697
+ - You genuinely cannot deliver what the user asked for despite trying.
2698
+
2699
+ When NOT to call:
2700
+ - Normal clarifying questions or back-and-forth with the user.
2701
+ - A single tool error that you can recover from or retry.
2702
+ - You successfully completed the task, even if it was difficult.
2703
+ - Policy refusals or content filtering \u2014 those are working as intended.
2704
+
2705
+ Rules:
2706
+ 1. Pick the single best category.
2707
+ 2. Do not fabricate issues. Only report what is evident from the conversation.
2708
+ 3. Err on the side of NOT calling this tool. When in doubt, help the user instead.
2709
+ ${guidanceBlock}
2710
+ Categories:
2711
+ ` + signalList;
2712
+ return {
2713
+ toolName,
2714
+ toolDescription,
2715
+ signalKeys,
2716
+ signalKeySet: new Set(signalKeys),
2717
+ signalDescriptions,
2718
+ signalSentiments
2719
+ };
2720
+ }
2721
+ function normalizeSelfDiagnosticsConfig(options) {
2722
+ if (!(options == null ? void 0 : options.enabled)) return void 0;
2723
+ return resolveSelfDiagnosticsConfig(options);
2724
+ }
2725
+ function asVercelSchema(inputSchema) {
2726
+ const validatorSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.validator");
2727
+ const schemaSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.schema");
2728
+ return {
2729
+ [schemaSymbol]: true,
2730
+ [validatorSymbol]: true,
2731
+ _type: void 0,
2732
+ jsonSchema: inputSchema,
2733
+ validate: (value) => ({ success: true, value })
2734
+ };
2735
+ }
2736
+ function resolveStandaloneEventId(options) {
2737
+ var _a, _b, _c, _d, _e, _f;
2738
+ return (_f = (_d = (_b = normalizeString((_a = options.getEventId) == null ? void 0 : _a.call(options))) != null ? _b : normalizeString(options.eventId)) != null ? _d : normalizeString((_c = getContextManager().getParentSpanIds()) == null ? void 0 : _c.eventId)) != null ? _f : normalizeString((_e = getCurrentRaindropCallMetadata()) == null ? void 0 : _e.eventId);
2739
+ }
2740
+ function createSelfDiagnosticsToolDefinition(args) {
2741
+ const { config, eventShipper, getEventId, aiSDKVersion, debug } = args;
2742
+ const inputJsonSchema = {
2743
+ type: "object",
2744
+ additionalProperties: false,
2745
+ properties: {
2746
+ category: {
2747
+ type: "string",
2748
+ enum: config.signalKeys,
2749
+ description: "The single best-matching category from the list above."
2750
+ },
2751
+ detail: {
2752
+ type: "string",
2753
+ description: "One sentence of factual context: what happened and why it matters. Do not include PII or secrets."
2754
+ }
2755
+ },
2756
+ required: ["category", "detail"]
2757
+ };
2758
+ const inputSchema = asVercelSchema(inputJsonSchema);
2759
+ const execute = async (rawInput) => {
2760
+ var _a, _b;
2761
+ const fallbackCategory = (_a = config.signalKeys[0]) != null ? _a : "unknown";
2762
+ const categoryCandidate = normalizeString(rawInput == null ? void 0 : rawInput.category);
2763
+ const category = categoryCandidate && config.signalKeySet.has(categoryCandidate) ? categoryCandidate : fallbackCategory;
2764
+ const detail = normalizeString(rawInput == null ? void 0 : rawInput.detail);
2765
+ const eventId = getEventId();
2766
+ if (!eventId) {
2767
+ const message = "self diagnostics signal skipped: missing eventId. Pass eventId or getEventId when creating the tool.";
2768
+ if (args.onMissingEventId === "throw") {
2769
+ throw new Error(`[raindrop-ai/ai-sdk] ${message}`);
2770
+ }
2771
+ if (((_b = args.onMissingEventId) != null ? _b : "warn") === "warn") {
2772
+ console.warn(`[raindrop-ai/ai-sdk] ${message}`);
2773
+ }
2774
+ return { acknowledged: false, category, reason: "missing_event_id" };
2775
+ }
2776
+ void eventShipper.trackSignal({
2777
+ eventId,
2778
+ name: `self diagnostics - ${category}`,
2779
+ type: "agent",
2780
+ sentiment: config.signalSentiments[category],
2781
+ properties: {
2782
+ source: "agent_reporting_tool",
2783
+ category,
2784
+ signal_description: config.signalDescriptions[category],
2785
+ ...aiSDKVersion ? { ai_sdk_version: aiSDKVersion } : {},
2786
+ ...detail ? { detail } : {}
2787
+ }
2788
+ }).catch((error) => {
2789
+ if (debug) {
2790
+ const message = error instanceof Error ? error.message : String(error);
2791
+ console.warn(`[raindrop-ai/ai-sdk] selfDiagnostics signal dispatch failed: ${message}`);
2792
+ }
2793
+ });
2794
+ return { acknowledged: true, category };
2795
+ };
2796
+ return {
2797
+ name: config.toolName,
2798
+ description: config.toolDescription,
2799
+ parameters: inputSchema,
2800
+ inputSchema,
2801
+ execute
2802
+ };
2803
+ }
2804
+ function createStandaloneSelfDiagnosticsTool(args) {
2805
+ const config = resolveSelfDiagnosticsConfig(args.options);
2806
+ return createSelfDiagnosticsToolDefinition({
2807
+ config,
2808
+ eventShipper: args.eventShipper,
2809
+ getEventId: () => resolveStandaloneEventId(args.options),
2810
+ onMissingEventId: args.options.onMissingEventId,
2811
+ debug: args.debug
2812
+ });
2813
+ }
2814
+
2815
+ // src/internal/traces.ts
2816
+ var TraceShipper2 = class extends TraceShipper {
2817
+ constructor(opts) {
2818
+ var _a, _b, _c;
2819
+ super({
2820
+ ...opts,
2821
+ sdkName: (_a = opts.sdkName) != null ? _a : "ai-sdk",
2822
+ serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.ai-sdk",
2823
+ serviceVersion: (_c = opts.serviceVersion) != null ? _c : libraryVersion
2824
+ });
2825
+ }
2826
+ };
2827
+
2828
+ // src/internal/wrap/wrapAISDK.ts
2509
2829
  var pendingStoresByShipper = /* @__PURE__ */ new WeakMap();
2510
2830
  var PendingToolSpanStore = class _PendingToolSpanStore {
2511
2831
  constructor() {
@@ -2609,85 +2929,6 @@ function mergeContexts(wrapTime, callTime) {
2609
2929
  }
2610
2930
  return result;
2611
2931
  }
2612
- function normalizeSelfDiagnosticsSignals(signals) {
2613
- if (!signals) return AGENT_REPORTING_SIGNALS_DEFAULT;
2614
- const normalizedEntries = Object.entries(signals).map(([key, value]) => {
2615
- var _a;
2616
- const signalKey = key.trim();
2617
- if (!signalKey || !value || typeof value !== "object") return void 0;
2618
- const description = (_a = value.description) == null ? void 0 : _a.trim();
2619
- if (!description) return void 0;
2620
- const sentiment = value.sentiment;
2621
- return [
2622
- signalKey,
2623
- {
2624
- description,
2625
- ...sentiment === "POSITIVE" || sentiment === "NEGATIVE" ? { sentiment } : {}
2626
- }
2627
- ];
2628
- }).filter(
2629
- (entry) => entry !== void 0
2630
- );
2631
- if (normalizedEntries.length === 0) return AGENT_REPORTING_SIGNALS_DEFAULT;
2632
- return Object.fromEntries(normalizedEntries);
2633
- }
2634
- function normalizeSelfDiagnosticsConfig(options) {
2635
- var _a, _b;
2636
- if (!(options == null ? void 0 : options.enabled)) return void 0;
2637
- const signalDefinitions = normalizeSelfDiagnosticsSignals(options.signals);
2638
- const signalKeys = Object.keys(signalDefinitions);
2639
- const signalDescriptions = {};
2640
- const signalSentiments = {};
2641
- for (const signalKey of signalKeys) {
2642
- const def = signalDefinitions[signalKey];
2643
- if (!def) continue;
2644
- signalDescriptions[signalKey] = def.description;
2645
- signalSentiments[signalKey] = def.sentiment;
2646
- }
2647
- const customGuidanceText = ((_a = options.guidance) == null ? void 0 : _a.trim()) || "";
2648
- const toolName = ((_b = options.toolName) == null ? void 0 : _b.trim()) || AGENT_REPORTING_TOOL_NAME_DEFAULT;
2649
- const signalList = signalKeys.map((signalKey) => {
2650
- const sentiment = signalSentiments[signalKey];
2651
- const sentimentTag = sentiment ? ` [${sentiment.toLowerCase()}]` : "";
2652
- return `- ${signalKey}: ${signalDescriptions[signalKey]}${sentimentTag}`;
2653
- }).join("\n");
2654
- const guidanceBlock = customGuidanceText ? `
2655
- Additional guidance: ${customGuidanceText}
2656
- ` : "";
2657
- const toolDescription = `${AGENT_REPORTING_TOOL_PREAMBLE}
2658
-
2659
- When to call:
2660
- - You are blocked from completing the task due to missing information or access that the user cannot provide.
2661
- - A tool is persistently failing across multiple attempts, not just a single transient error.
2662
- - The task requires a tool, permission, or capability you do not have.
2663
- - You genuinely cannot deliver what the user asked for despite trying.
2664
-
2665
- When NOT to call:
2666
- - Normal clarifying questions or back-and-forth with the user.
2667
- - A single tool error that you can recover from or retry.
2668
- - You successfully completed the task, even if it was difficult.
2669
- - Policy refusals or content filtering \u2014 those are working as intended.
2670
-
2671
- Rules:
2672
- 1. Pick the single best category.
2673
- 2. Do not fabricate issues. Only report what is evident from the conversation.
2674
- 3. Err on the side of NOT calling this tool. When in doubt, help the user instead.
2675
- ${guidanceBlock}
2676
- Categories:
2677
- ${signalList}`;
2678
- return {
2679
- toolName,
2680
- toolDescription,
2681
- signalKeys,
2682
- signalKeySet: new Set(signalKeys),
2683
- signalDescriptions,
2684
- signalSentiments
2685
- };
2686
- }
2687
- function resolveJsonSchemaFactory(aiSDK) {
2688
- if (!isRecord(aiSDK) || !isFunction(aiSDK["jsonSchema"])) return void 0;
2689
- return aiSDK["jsonSchema"];
2690
- }
2691
2932
  function detectAISDKVersion(aiSDK) {
2692
2933
  if (!isRecord(aiSDK)) return "unknown";
2693
2934
  if (isFunction(aiSDK["jsonSchema"])) return "6";
@@ -2706,80 +2947,16 @@ function resolveRegisterTelemetry(aiSDK) {
2706
2947
  const fn = (_a = aiSDK["registerTelemetry"]) != null ? _a : aiSDK["registerTelemetryIntegration"];
2707
2948
  return isFunction(fn) ? fn : void 0;
2708
2949
  }
2709
- function asVercelSchema(jsonSchemaObj) {
2710
- const validatorSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.validator");
2711
- const schemaSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.schema");
2712
- return {
2713
- [schemaSymbol]: true,
2714
- [validatorSymbol]: true,
2715
- _type: void 0,
2716
- jsonSchema: jsonSchemaObj,
2717
- validate: (value) => ({ success: true, value })
2718
- };
2719
- }
2720
2950
  function createSelfDiagnosticsTool(ctx) {
2721
2951
  const config = ctx.selfDiagnostics;
2722
2952
  if (!config) return void 0;
2723
- const schema = {
2724
- type: "object",
2725
- additionalProperties: false,
2726
- properties: {
2727
- category: {
2728
- type: "string",
2729
- enum: config.signalKeys,
2730
- description: "The single best-matching category from the list above."
2731
- },
2732
- detail: {
2733
- type: "string",
2734
- description: "One sentence of factual context: what happened and why it matters. Do not include PII or secrets."
2735
- }
2736
- },
2737
- required: ["category", "detail"]
2738
- };
2739
- const parameters = asVercelSchema(schema);
2740
- let inputSchema = parameters;
2741
- if (ctx.jsonSchemaFactory) {
2742
- try {
2743
- inputSchema = ctx.jsonSchemaFactory(schema);
2744
- } catch (e) {
2745
- inputSchema = parameters;
2746
- }
2747
- }
2748
- const execute = async (rawInput) => {
2749
- var _a;
2750
- const input = isRecord(rawInput) ? rawInput : void 0;
2751
- const fallbackCategory = (_a = config.signalKeys[0]) != null ? _a : "unknown";
2752
- const categoryCandidate = typeof (input == null ? void 0 : input["category"]) === "string" ? input["category"].trim() : void 0;
2753
- const category = categoryCandidate && config.signalKeySet.has(categoryCandidate) ? categoryCandidate : fallbackCategory;
2754
- const detail = typeof (input == null ? void 0 : input["detail"]) === "string" ? input["detail"].trim() : "";
2755
- const signalDescription = config.signalDescriptions[category];
2756
- const signalSentiment = config.signalSentiments[category];
2757
- void ctx.eventShipper.trackSignal({
2758
- eventId: ctx.eventId,
2759
- name: `self diagnostics - ${category}`,
2760
- type: "agent",
2761
- sentiment: signalSentiment,
2762
- properties: {
2763
- source: "agent_reporting_tool",
2764
- category,
2765
- signal_description: signalDescription,
2766
- ai_sdk_version: ctx.aiSDKVersion,
2767
- ...detail ? { detail } : {}
2768
- }
2769
- }).catch((err) => {
2770
- if (ctx.debug) {
2771
- const msg = err instanceof Error ? err.message : String(err);
2772
- console.warn(`[raindrop-ai/ai-sdk] selfDiagnostics signal dispatch failed: ${msg}`);
2773
- }
2774
- });
2775
- return { acknowledged: true, category };
2776
- };
2777
- return {
2778
- description: config.toolDescription,
2779
- execute,
2780
- parameters,
2781
- inputSchema
2782
- };
2953
+ return createSelfDiagnosticsToolDefinition({
2954
+ config,
2955
+ eventShipper: ctx.eventShipper,
2956
+ getEventId: () => ctx.eventId,
2957
+ aiSDKVersion: ctx.aiSDKVersion,
2958
+ debug: ctx.debug
2959
+ });
2783
2960
  }
2784
2961
  function getCurrentParentSpanContextSync() {
2785
2962
  return getContextManager().getParentSpanIds();
@@ -3006,7 +3183,6 @@ function setupOperation(params) {
3006
3183
  eventShipper,
3007
3184
  traceShipper,
3008
3185
  rootParentForChildren,
3009
- jsonSchemaFactory: resolveJsonSchemaFactory(aiSDK),
3010
3186
  selfDiagnostics: operationSelfDiagnostics,
3011
3187
  aiSDKVersion: detectAISDKVersion(aiSDK)
3012
3188
  };
@@ -3355,7 +3531,6 @@ function wrapAISDK(aiSDK, deps) {
3355
3531
  );
3356
3532
  }
3357
3533
  const selfDiagnostics2 = normalizeSelfDiagnosticsConfig(deps.options.selfDiagnostics);
3358
- const jsonSchemaFactory = selfDiagnostics2 ? resolveJsonSchemaFactory(aiSDK) : void 0;
3359
3534
  const metadataAwareOps = /* @__PURE__ */ new Set([
3360
3535
  "generateText",
3361
3536
  "streamText",
@@ -3387,14 +3562,9 @@ function wrapAISDK(aiSDK, deps) {
3387
3562
  const perCallEventIdGenerated = !perCallEventIdExplicit;
3388
3563
  const perCallCtx = {
3389
3564
  eventId: perCallEventId,
3390
- context: wrapTimeCtx,
3391
- telemetry,
3392
- sendTraces: false,
3393
3565
  debug,
3394
3566
  eventShipper: deps.eventShipper,
3395
3567
  traceShipper: deps.traceShipper,
3396
- rootParentForChildren: void 0,
3397
- jsonSchemaFactory,
3398
3568
  selfDiagnostics: selfDiagnostics2,
3399
3569
  aiSDKVersion: "7"
3400
3570
  };
@@ -3596,7 +3766,6 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
3596
3766
  eventShipper: deps.eventShipper,
3597
3767
  traceShipper: deps.traceShipper,
3598
3768
  rootParentForChildren,
3599
- jsonSchemaFactory: resolveJsonSchemaFactory(aiSDK),
3600
3769
  selfDiagnostics,
3601
3770
  aiSDKVersion: detectAISDKVersion(aiSDK)
3602
3771
  };
@@ -3804,7 +3973,6 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
3804
3973
  eventShipper: deps.eventShipper,
3805
3974
  traceShipper: deps.traceShipper,
3806
3975
  rootParentForChildren,
3807
- jsonSchemaFactory: resolveJsonSchemaFactory(aiSDK),
3808
3976
  selfDiagnostics,
3809
3977
  aiSDKVersion: detectAISDKVersion(aiSDK)
3810
3978
  };
@@ -4620,6 +4788,14 @@ function createRaindropAISDK(opts) {
4620
4788
  traceShipper
4621
4789
  });
4622
4790
  },
4791
+ createSelfDiagnosticsTool(options = {}) {
4792
+ var _a2;
4793
+ return createStandaloneSelfDiagnosticsTool({
4794
+ options,
4795
+ eventShipper,
4796
+ debug: ((_a2 = opts.events) == null ? void 0 : _a2.debug) === true || envDebug
4797
+ });
4798
+ },
4623
4799
  createTelemetryIntegration(contextOrOptions) {
4624
4800
  const FLAT_CONTEXT_KEYS = [
4625
4801
  "userId",
@@ -4750,6 +4926,13 @@ function createRaindropAISDK(opts) {
4750
4926
  }
4751
4927
  };
4752
4928
  }
4929
+ function raindrop(options = {}) {
4930
+ var _a;
4931
+ const { context, subagentWrapping, writeKey, ...rest } = options;
4932
+ const resolvedWriteKey = writeKey != null ? writeKey : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.RAINDROP_WRITE_KEY : void 0;
4933
+ const client = createRaindropAISDK({ ...rest, writeKey: resolvedWriteKey });
4934
+ return client.createTelemetryIntegration({ context, subagentWrapping });
4935
+ }
4753
4936
 
4754
4937
  // src/index.node.ts
4755
4938
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
@@ -4771,6 +4954,7 @@ exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
4771
4954
  exports.getContextManager = getContextManager;
4772
4955
  exports.getCurrentParentToolContext = getCurrentParentToolContext;
4773
4956
  exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
4957
+ exports.raindrop = raindrop;
4774
4958
  exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
4775
4959
  exports.redactJsonAttributeValue = redactJsonAttributeValue;
4776
4960
  exports.redactSecretsInObject = redactSecretsInObject;