raindrop-ai 0.2.4 → 0.3.0

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/dist/index.js CHANGED
@@ -720,11 +720,11 @@ var require_lodash = __commonJS({
720
720
  function unicodeWords(string) {
721
721
  return string.match(reUnicodeWord) || [];
722
722
  }
723
- var runInContext = (function runInContext2(context5) {
724
- context5 = context5 == null ? root : _.defaults(root.Object(), context5, _.pick(root, contextProps));
725
- var Array2 = context5.Array, Date2 = context5.Date, Error2 = context5.Error, Function2 = context5.Function, Math2 = context5.Math, Object2 = context5.Object, RegExp2 = context5.RegExp, String2 = context5.String, TypeError2 = context5.TypeError;
723
+ var runInContext = (function runInContext2(context6) {
724
+ context6 = context6 == null ? root : _.defaults(root.Object(), context6, _.pick(root, contextProps));
725
+ var Array2 = context6.Array, Date2 = context6.Date, Error2 = context6.Error, Function2 = context6.Function, Math2 = context6.Math, Object2 = context6.Object, RegExp2 = context6.RegExp, String2 = context6.String, TypeError2 = context6.TypeError;
726
726
  var arrayProto = Array2.prototype, funcProto = Function2.prototype, objectProto = Object2.prototype;
727
- var coreJsData = context5["__core-js_shared__"];
727
+ var coreJsData = context6["__core-js_shared__"];
728
728
  var funcToString = funcProto.toString;
729
729
  var hasOwnProperty = objectProto.hasOwnProperty;
730
730
  var idCounter = 0;
@@ -738,7 +738,7 @@ var require_lodash = __commonJS({
738
738
  var reIsNative = RegExp2(
739
739
  "^" + funcToString.call(hasOwnProperty).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$"
740
740
  );
741
- var Buffer2 = moduleExports ? context5.Buffer : undefined2, Symbol2 = context5.Symbol, Uint8Array2 = context5.Uint8Array, allocUnsafe = Buffer2 ? Buffer2.allocUnsafe : undefined2, getPrototype = overArg(Object2.getPrototypeOf, Object2), objectCreate = Object2.create, propertyIsEnumerable = objectProto.propertyIsEnumerable, splice = arrayProto.splice, spreadableSymbol = Symbol2 ? Symbol2.isConcatSpreadable : undefined2, symIterator = Symbol2 ? Symbol2.iterator : undefined2, symToStringTag = Symbol2 ? Symbol2.toStringTag : undefined2;
741
+ var Buffer2 = moduleExports ? context6.Buffer : undefined2, Symbol2 = context6.Symbol, Uint8Array2 = context6.Uint8Array, allocUnsafe = Buffer2 ? Buffer2.allocUnsafe : undefined2, getPrototype = overArg(Object2.getPrototypeOf, Object2), objectCreate = Object2.create, propertyIsEnumerable = objectProto.propertyIsEnumerable, splice = arrayProto.splice, spreadableSymbol = Symbol2 ? Symbol2.isConcatSpreadable : undefined2, symIterator = Symbol2 ? Symbol2.iterator : undefined2, symToStringTag = Symbol2 ? Symbol2.toStringTag : undefined2;
742
742
  var defineProperty = (function() {
743
743
  try {
744
744
  var func = getNative(Object2, "defineProperty");
@@ -747,9 +747,9 @@ var require_lodash = __commonJS({
747
747
  } catch (e) {
748
748
  }
749
749
  })();
750
- var ctxClearTimeout = context5.clearTimeout !== root.clearTimeout && context5.clearTimeout, ctxNow = Date2 && Date2.now !== root.Date.now && Date2.now, ctxSetTimeout = context5.setTimeout !== root.setTimeout && context5.setTimeout;
751
- var nativeCeil = Math2.ceil, nativeFloor = Math2.floor, nativeGetSymbols = Object2.getOwnPropertySymbols, nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : undefined2, nativeIsFinite = context5.isFinite, nativeJoin = arrayProto.join, nativeKeys = overArg(Object2.keys, Object2), nativeMax = Math2.max, nativeMin = Math2.min, nativeNow = Date2.now, nativeParseInt = context5.parseInt, nativeRandom = Math2.random, nativeReverse = arrayProto.reverse;
752
- var DataView = getNative(context5, "DataView"), Map2 = getNative(context5, "Map"), Promise2 = getNative(context5, "Promise"), Set2 = getNative(context5, "Set"), WeakMap = getNative(context5, "WeakMap"), nativeCreate = getNative(Object2, "create");
750
+ var ctxClearTimeout = context6.clearTimeout !== root.clearTimeout && context6.clearTimeout, ctxNow = Date2 && Date2.now !== root.Date.now && Date2.now, ctxSetTimeout = context6.setTimeout !== root.setTimeout && context6.setTimeout;
751
+ var nativeCeil = Math2.ceil, nativeFloor = Math2.floor, nativeGetSymbols = Object2.getOwnPropertySymbols, nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : undefined2, nativeIsFinite = context6.isFinite, nativeJoin = arrayProto.join, nativeKeys = overArg(Object2.keys, Object2), nativeMax = Math2.max, nativeMin = Math2.min, nativeNow = Date2.now, nativeParseInt = context6.parseInt, nativeRandom = Math2.random, nativeReverse = arrayProto.reverse;
752
+ var DataView = getNative(context6, "DataView"), Map2 = getNative(context6, "Map"), Promise2 = getNative(context6, "Promise"), Set2 = getNative(context6, "Set"), WeakMap = getNative(context6, "WeakMap"), nativeCreate = getNative(Object2, "create");
753
753
  var metaMap = WeakMap && new WeakMap();
754
754
  var realNames = {};
755
755
  var dataViewCtorString = toSource(DataView), mapCtorString = toSource(Map2), promiseCtorString = toSource(Promise2), setCtorString = toSource(Set2), weakMapCtorString = toSource(WeakMap);
@@ -5778,7 +5778,7 @@ if (!globalThis.RAINDROP_ASYNC_LOCAL_STORAGE) {
5778
5778
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_node_async_hooks.AsyncLocalStorage;
5779
5779
  }
5780
5780
 
5781
- // ../core/dist/chunk-QTUH3BHZ.js
5781
+ // ../core/dist/chunk-YUIXRQWN.js
5782
5782
  function normalizeFeatureFlags(input) {
5783
5783
  if (Array.isArray(input)) {
5784
5784
  return Object.fromEntries(input.map((name) => [name, "true"]));
@@ -5787,6 +5787,293 @@ function normalizeFeatureFlags(input) {
5787
5787
  Object.entries(input).map(([k, v]) => [k, String(v)])
5788
5788
  );
5789
5789
  }
5790
+ function getCrypto() {
5791
+ const c = globalThis.crypto;
5792
+ return c;
5793
+ }
5794
+ function randomBytes(length) {
5795
+ const cryptoObj = getCrypto();
5796
+ const out = new Uint8Array(length);
5797
+ if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
5798
+ cryptoObj.getRandomValues(out);
5799
+ return out;
5800
+ }
5801
+ for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
5802
+ return out;
5803
+ }
5804
+ function randomUUID() {
5805
+ const cryptoObj = getCrypto();
5806
+ if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
5807
+ return cryptoObj.randomUUID();
5808
+ }
5809
+ const b = randomBytes(16);
5810
+ b[6] = b[6] & 15 | 64;
5811
+ b[8] = b[8] & 63 | 128;
5812
+ const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
5813
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
5814
+ }
5815
+ var HANDOFF_ATTRIBUTE_SUFFIXES = {
5816
+ mode: "raindrop.handoff.mode",
5817
+ childEventId: "raindrop.handoff.childEventId",
5818
+ parentEventId: "raindrop.handoff.parentEventId",
5819
+ parentSpanId: "raindrop.handoff.parentSpanId",
5820
+ name: "raindrop.handoff.name",
5821
+ terminal: "raindrop.handoff.terminal",
5822
+ agentRole: "raindrop.agent.role"
5823
+ };
5824
+ var AI_SDK_METADATA_PREFIX = "ai.telemetry.metadata.";
5825
+ var DETACHED_MODE = "detached";
5826
+ var SUBAGENT_AGENT_ROLE = "subagent";
5827
+ var HANDOFF_TERMINAL_CANCELLED = "cancelled";
5828
+ var TOOL_EVENTS_SUFFIX = "raindrop.toolEvents";
5829
+ var TOOL_EVENTS_ALLOW = "allow";
5830
+ var OPERATION_ID_ATTRIBUTE = "ai.operationId";
5831
+ var SUBAGENT_ABORT_OPERATION_ID = "ai.subagent.failed";
5832
+ var SUBAGENT_ABORT_SPAN_NAME = SUBAGENT_ABORT_OPERATION_ID;
5833
+ var DEFAULT_DISPATCH_SPAN_NAME = "launch_subagent";
5834
+ var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
5835
+ function defined(entries) {
5836
+ const out = {};
5837
+ for (const [key, value] of Object.entries(entries)) {
5838
+ if (typeof value === "string" && value.trim().length > 0) out[key] = value;
5839
+ }
5840
+ return out;
5841
+ }
5842
+ function detachedDispatchMetadata(dispatch) {
5843
+ return defined({
5844
+ [HANDOFF_ATTRIBUTE_SUFFIXES.mode]: DETACHED_MODE,
5845
+ [HANDOFF_ATTRIBUTE_SUFFIXES.childEventId]: dispatch.childEventId,
5846
+ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: dispatch.name
5847
+ });
5848
+ }
5849
+ function detachedChildMetadata(link) {
5850
+ return defined({
5851
+ [HANDOFF_ATTRIBUTE_SUFFIXES.parentEventId]: link.parentEventId,
5852
+ [HANDOFF_ATTRIBUTE_SUFFIXES.parentSpanId]: link.parentSpanId,
5853
+ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: link.name,
5854
+ [HANDOFF_ATTRIBUTE_SUFFIXES.agentRole]: SUBAGENT_AGENT_ROLE
5855
+ });
5856
+ }
5857
+ function cancelledTerminalMetadata() {
5858
+ return { [HANDOFF_ATTRIBUTE_SUFFIXES.terminal]: HANDOFF_TERMINAL_CANCELLED };
5859
+ }
5860
+ function cancelledTerminalAttributes() {
5861
+ const bare = cancelledTerminalMetadata();
5862
+ return { ...bare, ...withMetadataPrefix(bare) };
5863
+ }
5864
+ function toolEventsAllowMetadata() {
5865
+ return { [TOOL_EVENTS_SUFFIX]: TOOL_EVENTS_ALLOW };
5866
+ }
5867
+ function withMetadataPrefix(metadata) {
5868
+ const out = {};
5869
+ for (const [key, value] of Object.entries(metadata)) {
5870
+ out[key.startsWith(AI_SDK_METADATA_PREFIX) ? key : `${AI_SDK_METADATA_PREFIX}${key}`] = value;
5871
+ }
5872
+ return out;
5873
+ }
5874
+ var BAGGAGE_KEYS = {
5875
+ eventId: "raindrop-event-id",
5876
+ childEventId: "raindrop-child-event-id",
5877
+ name: "raindrop-handoff-name",
5878
+ convoId: "raindrop-convo-id",
5879
+ userId: "raindrop-user-id",
5880
+ // The dispatch span and its trace, carried as fields as well as in
5881
+ // `traceparent`. Not redundant: OTel's HTTP instrumentations rewrite
5882
+ // `traceparent` from whatever span is current as the request goes out, so by
5883
+ // the time the child reads it the ids name the HTTP client span and its trace
5884
+ // instead of the dispatch. The child would then point its reverse reference at
5885
+ // a span the launcher's UI does not know as a dispatch. A field states which
5886
+ // span it means rather than meaning "whoever wrote this header last".
5887
+ dispatchSpanId: "raindrop-dispatch-span-id",
5888
+ traceId: "raindrop-trace-id"
5889
+ };
5890
+ var TRACEPARENT_HEADER = "traceparent";
5891
+ var BAGGAGE_HEADER = "baggage";
5892
+ var W3C_TRACE_ID = /^[0-9a-f]{32}$/;
5893
+ var W3C_SPAN_ID = /^[0-9a-f]{16}$/;
5894
+ function isW3CTraceId(value) {
5895
+ return value !== void 0 && W3C_TRACE_ID.test(value);
5896
+ }
5897
+ function isW3CSpanId(value) {
5898
+ return value !== void 0 && W3C_SPAN_ID.test(value);
5899
+ }
5900
+ var warnedNonConformantIds = false;
5901
+ function warnNonConformantIdsOnce(traceId, spanId) {
5902
+ if (warnedNonConformantIds) return;
5903
+ warnedNonConformantIds = true;
5904
+ console.warn(
5905
+ `[raindrop] hand-off carrier ids are not W3C-shaped (traceId="${traceId}", spanId="${spanId}"). The child still reports as its own event, but its reverse reference names a span id the backend does not store, so the link back to the launcher will not resolve. A LangSmith carrier reads this way \u2014 its run ids are UUIDs; propagate Raindrop's own carrier (toHeaders) to link.`
5906
+ );
5907
+ }
5908
+ var HANDOFF_HEADER = "x-raindrop-handoff";
5909
+ var LANGSMITH_TRACE_HEADER = "langsmith-trace";
5910
+ var LANGSMITH_METADATA_BAGGAGE_KEY = "langsmith-metadata";
5911
+ function encodeBaggage(entries) {
5912
+ return Object.entries(entries).filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join(",");
5913
+ }
5914
+ function decodeBaggage(header) {
5915
+ if (!header) return {};
5916
+ const parsed = {};
5917
+ for (const part of header.split(",")) {
5918
+ const [rawKey, ...rest] = part.split("=");
5919
+ if (!rawKey || rest.length === 0) continue;
5920
+ const key = rawKey.trim();
5921
+ let value;
5922
+ try {
5923
+ value = decodeURIComponent(rest.join("=").trim());
5924
+ } catch (e) {
5925
+ value = rest.join("=").trim();
5926
+ }
5927
+ if (key in parsed && parsed[key] !== value) throw new ConflictingCarrierError(key);
5928
+ parsed[key] = value;
5929
+ }
5930
+ return parsed;
5931
+ }
5932
+ function carrierBaggage(carrier) {
5933
+ return {
5934
+ [BAGGAGE_KEYS.eventId]: carrier.eventId,
5935
+ [BAGGAGE_KEYS.childEventId]: carrier.childEventId,
5936
+ [BAGGAGE_KEYS.name]: carrier.name,
5937
+ [BAGGAGE_KEYS.convoId]: carrier.convoId,
5938
+ [BAGGAGE_KEYS.userId]: carrier.userId,
5939
+ [BAGGAGE_KEYS.dispatchSpanId]: carrier.spanId,
5940
+ [BAGGAGE_KEYS.traceId]: carrier.traceId
5941
+ };
5942
+ }
5943
+ function toHeaders(carrier) {
5944
+ const fields = encodeBaggage(carrierBaggage(carrier));
5945
+ const headers = {
5946
+ [BAGGAGE_HEADER]: fields,
5947
+ [HANDOFF_HEADER]: fields
5948
+ };
5949
+ if (isW3CTraceId(carrier.traceId) && isW3CSpanId(carrier.spanId)) {
5950
+ headers[TRACEPARENT_HEADER] = `00-${carrier.traceId}-${carrier.spanId}-01`;
5951
+ }
5952
+ return headers;
5953
+ }
5954
+ function langsmithStamp() {
5955
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "000000");
5956
+ }
5957
+ function toLangSmithHeaders(carrier) {
5958
+ const stamp = langsmithStamp();
5959
+ const dottedOrder = `${stamp}Z${carrier.traceId}.${stamp}Z${carrier.spanId}`;
5960
+ return {
5961
+ [LANGSMITH_TRACE_HEADER]: dottedOrder,
5962
+ [BAGGAGE_HEADER]: encodeBaggage({
5963
+ [LANGSMITH_METADATA_BAGGAGE_KEY]: JSON.stringify(carrierBaggage(carrier))
5964
+ }),
5965
+ // Carried here too: a LangSmith-shaped carrier is rewritten in transit
5966
+ // exactly like the native one, and an injected `traceparent` is preferred
5967
+ // over the dotted order on read.
5968
+ [HANDOFF_HEADER]: encodeBaggage(carrierBaggage(carrier))
5969
+ };
5970
+ }
5971
+ function isHeaderLookup(headers) {
5972
+ return "get" in headers && typeof headers.get === "function";
5973
+ }
5974
+ var ConflictingCarrierError = class extends Error {
5975
+ };
5976
+ function readHeader(headers, name) {
5977
+ var _a, _b, _c;
5978
+ if (isHeaderLookup(headers)) return (_a = headers.get(name)) != null ? _a : void 0;
5979
+ const value = (_c = headers[name]) != null ? _c : (_b = Object.entries(headers).find(([key]) => key.toLowerCase() === name)) == null ? void 0 : _b[1];
5980
+ if (!Array.isArray(value)) return value;
5981
+ const distinct = new Set(value);
5982
+ if (distinct.size > 1) throw new ConflictingCarrierError(name);
5983
+ return value[0];
5984
+ }
5985
+ function readTraceHeader(headers, name) {
5986
+ const value = readHeader(headers, name);
5987
+ if (!(value == null ? void 0 : value.includes(","))) return value;
5988
+ const copies = value.split(",").map((copy) => copy.trim());
5989
+ if (new Set(copies).size > 1) throw new ConflictingCarrierError(name);
5990
+ return copies[0];
5991
+ }
5992
+ function fromHeaders(headers) {
5993
+ var _a, _b;
5994
+ let baggage;
5995
+ let handoff;
5996
+ let traceparent;
5997
+ let langsmithTrace;
5998
+ try {
5999
+ baggage = decodeBaggage(readHeader(headers, BAGGAGE_HEADER));
6000
+ handoff = decodeBaggage(readHeader(headers, HANDOFF_HEADER));
6001
+ traceparent = readTraceHeader(headers, TRACEPARENT_HEADER);
6002
+ langsmithTrace = readTraceHeader(headers, LANGSMITH_TRACE_HEADER);
6003
+ } catch (error) {
6004
+ if (error instanceof ConflictingCarrierError) return null;
6005
+ throw error;
6006
+ }
6007
+ const langsmithMetadata = baggage[LANGSMITH_METADATA_BAGGAGE_KEY];
6008
+ const nested = langsmithMetadata ? safeParseStringRecord(langsmithMetadata) : {};
6009
+ for (const [key, value] of Object.entries(nested)) {
6010
+ if (key in baggage && baggage[key] !== value) return null;
6011
+ }
6012
+ const fields = {
6013
+ ...baggage,
6014
+ ...nested,
6015
+ // Last, so it wins: the standard headers may have been rewritten in transit
6016
+ // by a propagator, this one is only ever written by us.
6017
+ ...handoff
6018
+ };
6019
+ let traceId;
6020
+ let spanId;
6021
+ if (traceparent) {
6022
+ const [, parsedTraceId, parsedSpanId] = traceparent.split("-");
6023
+ if (isW3CTraceId(parsedTraceId) && isW3CSpanId(parsedSpanId)) {
6024
+ traceId = parsedTraceId;
6025
+ spanId = parsedSpanId;
6026
+ }
6027
+ }
6028
+ if (!traceId && !spanId && langsmithTrace) {
6029
+ const segments = langsmithTrace.split(".");
6030
+ traceId = (_a = segments[0]) == null ? void 0 : _a.split("Z").pop();
6031
+ spanId = (_b = segments[segments.length - 1]) == null ? void 0 : _b.split("Z").pop();
6032
+ }
6033
+ traceId = fields[BAGGAGE_KEYS.traceId] || traceId;
6034
+ spanId = fields[BAGGAGE_KEYS.dispatchSpanId] || spanId;
6035
+ const eventId = fields[BAGGAGE_KEYS.eventId];
6036
+ if (!traceId || !spanId || !eventId) return null;
6037
+ if (!isW3CTraceId(traceId) || !isW3CSpanId(spanId)) {
6038
+ warnNonConformantIdsOnce(traceId, spanId);
6039
+ }
6040
+ const carrier = { traceId, spanId, eventId };
6041
+ const childEventId = fields[BAGGAGE_KEYS.childEventId];
6042
+ if (childEventId) carrier.childEventId = childEventId;
6043
+ const name = fields[BAGGAGE_KEYS.name];
6044
+ if (name) carrier.name = name;
6045
+ const convoId = fields[BAGGAGE_KEYS.convoId];
6046
+ if (convoId) carrier.convoId = convoId;
6047
+ const userId = fields[BAGGAGE_KEYS.userId];
6048
+ if (userId) carrier.userId = userId;
6049
+ return carrier;
6050
+ }
6051
+ var UNRESOLVED_CARRIER_WARNING = `[raindrop] resume: headers were supplied but no hand-off carrier was found on them (searched ${HANDOFF_HEADER}, ${TRACEPARENT_HEADER}, ${BAGGAGE_HEADER}). This run reports as an UNLINKED event, and the launcher that dispatched it will stay on "queued" forever because nothing ever references its child. Passing headers means a parent handed off, so no carrier on them is almost certainly a defect: a gateway or proxy stripping ${HANDOFF_HEADER}, a middleware overwriting ${BAGGAGE_HEADER}, a request forwarded without its headers, or a hand-built carrier whose field names do not match. Send every header the launcher's dispatch returned. Logged once per process; pass no headers for a directly-invoked sub-agent to silence it.`;
6052
+ var UNRESOLVED_CARRIER_WARNED_KEY = /* @__PURE__ */ Symbol.for("raindrop.handoff.warnedUnresolvedCarrier");
6053
+ function warnedHolder() {
6054
+ return globalThis;
6055
+ }
6056
+ function warnUnresolvedCarrier(headers, carrier) {
6057
+ if (carrier) return;
6058
+ if (!headers) return;
6059
+ const holder = warnedHolder();
6060
+ if (holder[UNRESOLVED_CARRIER_WARNED_KEY]) return;
6061
+ holder[UNRESOLVED_CARRIER_WARNED_KEY] = true;
6062
+ console.warn(UNRESOLVED_CARRIER_WARNING);
6063
+ }
6064
+ function safeParseStringRecord(raw) {
6065
+ try {
6066
+ const parsed = JSON.parse(raw);
6067
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
6068
+ const result = {};
6069
+ for (const [key, value] of Object.entries(parsed)) {
6070
+ if (typeof value === "string") result[key] = value;
6071
+ }
6072
+ return result;
6073
+ } catch (e) {
6074
+ return {};
6075
+ }
6076
+ }
5790
6077
  function runWithTracingSuppressed(fn) {
5791
6078
  const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
5792
6079
  if (typeof hook !== "function") return fn();
@@ -6168,6 +6455,62 @@ function projectIdHeaders(projectId) {
6168
6455
  }
6169
6456
  var SHUTDOWN_DEADLINE_MS = 1e4;
6170
6457
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
6458
+ var MODEL_USAGE_ATTRIBUTES = {
6459
+ providerName: "gen_ai.provider.name",
6460
+ requestModel: "gen_ai.request.model",
6461
+ responseModel: "gen_ai.response.model",
6462
+ inputTokens: "gen_ai.usage.input_tokens",
6463
+ outputTokens: "gen_ai.usage.output_tokens",
6464
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
6465
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
6466
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
6467
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
6468
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
6469
+ totalOutputTokens: "raindrop.usage.output_tokens.total",
6470
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
6471
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
6472
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
6473
+ };
6474
+ var STRING_ALIASES = {
6475
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
6476
+ };
6477
+ var NUMBER_ALIASES = {
6478
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
6479
+ "gen_ai.usage.prompt_tokens",
6480
+ "ai.usage.prompt_tokens",
6481
+ "ai.usage.promptTokens",
6482
+ "ai.usage.input_tokens",
6483
+ "ai.usage.inputTokens"
6484
+ ],
6485
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
6486
+ "gen_ai.usage.completion_tokens",
6487
+ "ai.usage.completion_tokens",
6488
+ "ai.usage.completionTokens",
6489
+ "ai.usage.output_tokens",
6490
+ "ai.usage.outputTokens"
6491
+ ],
6492
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
6493
+ "gen_ai.usage.reasoning.output_tokens",
6494
+ "ai.usage.reasoningTokens",
6495
+ "ai.usage.thoughts_tokens"
6496
+ ],
6497
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
6498
+ "gen_ai.usage.cache_read_tokens",
6499
+ "gen_ai.usage.cache_read.input_tokens",
6500
+ "ai.usage.cachedInputTokens",
6501
+ "ai.usage.cached_tokens",
6502
+ "ai.usage.cache_read_tokens",
6503
+ "ai.usage.cache_read_input_tokens",
6504
+ "ai.usage.cacheReadInputTokens"
6505
+ ],
6506
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
6507
+ "gen_ai.usage.cache_creation_input_tokens",
6508
+ "gen_ai.usage.cache_creation.input_tokens",
6509
+ "ai.usage.cacheWriteInputTokens",
6510
+ "ai.usage.cache_creation_input_tokens",
6511
+ "ai.usage.cacheCreationInputTokens"
6512
+ ]
6513
+ };
6171
6514
  var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
6172
6515
  "ai.request.providerOptions",
6173
6516
  "ai.response.providerMetadata"
@@ -6182,8 +6525,10 @@ function getWeakRefCtor() {
6182
6525
  }
6183
6526
  var MAX_BINDING_STACK = 128;
6184
6527
  var EMPTY_STACK = [];
6185
- var RoutingContextStorage = class {
6186
- constructor() {
6528
+ var ContextStackStorage = class {
6529
+ /** Emitted once when this runtime cannot support an ambient push. */
6530
+ constructor(noAmbientBindWarning) {
6531
+ this.noAmbientBindWarning = noAmbientBindWarning;
6187
6532
  this._als = null;
6188
6533
  this._enterWithUsable = false;
6189
6534
  this._syncStack = EMPTY_STACK;
@@ -6280,17 +6625,17 @@ var RoutingContextStorage = class {
6280
6625
  warnNoAmbientBindOnce() {
6281
6626
  if (this._warnedNoAmbientBind) return;
6282
6627
  this._warnedNoAmbientBind = true;
6283
- console.warn(
6284
- "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so begin()/finish() cannot scope auto-instrumented spans to a project without cross-contaminating concurrent requests. Manual events and explicit span routing are unaffected; use asCurrent()/withSpan (run-based) to route auto-instrumented spans on this runtime."
6285
- );
6628
+ console.warn(this.noAmbientBindWarning);
6286
6629
  }
6287
6630
  };
6631
+ var NO_AMBIENT_ROUTING_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so begin()/finish() cannot scope auto-instrumented spans to a project without cross-contaminating concurrent requests. Manual events and explicit span routing are unaffected; use asCurrent()/withSpan (run-based) to route auto-instrumented spans on this runtime.";
6632
+ var NO_AMBIENT_ATTRIBUTE_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so contextual span attributes (the detached sub-agent hand-off reference) cannot be bound ambiently without cross-contaminating concurrent requests. The child's own event still reports; only the per-span reverse reference is skipped.";
6288
6633
  var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
6289
6634
  function routingStorage() {
6290
6635
  const holder = globalThis;
6291
6636
  let storage = holder[ROUTING_STORAGE_KEY];
6292
6637
  if (!storage) {
6293
- storage = new RoutingContextStorage();
6638
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
6294
6639
  holder[ROUTING_STORAGE_KEY] = storage;
6295
6640
  }
6296
6641
  return storage;
@@ -6338,6 +6683,104 @@ function currentRoutingBinding() {
6338
6683
  function isBoundContext(value) {
6339
6684
  return typeof value.isLive === "function";
6340
6685
  }
6686
+ var ATTRIBUTE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.spanAttributeStorage");
6687
+ function attributeStorage() {
6688
+ const holder = globalThis;
6689
+ let storage = holder[ATTRIBUTE_STORAGE_KEY];
6690
+ if (!storage) {
6691
+ storage = new ContextStackStorage(NO_AMBIENT_ATTRIBUTE_BIND_WARNING);
6692
+ holder[ATTRIBUTE_STORAGE_KEY] = storage;
6693
+ }
6694
+ return storage;
6695
+ }
6696
+ function makeAttributeFrame(attributes, owner) {
6697
+ const snapshot = { ...attributes };
6698
+ const WeakRefCtor = owner !== void 0 ? getWeakRefCtor() : void 0;
6699
+ const ref = WeakRefCtor && owner !== void 0 ? new WeakRefCtor(owner) : void 0;
6700
+ const owned = /* @__PURE__ */ new WeakSet();
6701
+ let dead = false;
6702
+ let sawError = false;
6703
+ return {
6704
+ attributes: snapshot,
6705
+ sawErrorSpan: () => sawError,
6706
+ ownsSpan: (span) => owned.has(span),
6707
+ claimSpan(span) {
6708
+ owned.add(span);
6709
+ },
6710
+ markErrorSpanSeen() {
6711
+ sawError = true;
6712
+ },
6713
+ // A frame whose owner has been collected is dead even though nothing
6714
+ // unbound it: a run that never settles must not keep handing its reverse
6715
+ // reference to whatever runs next on a reused context.
6716
+ isLive() {
6717
+ if (dead) return false;
6718
+ return ref === void 0 || ref.deref() !== void 0;
6719
+ },
6720
+ markDead() {
6721
+ dead = true;
6722
+ }
6723
+ };
6724
+ }
6725
+ function bindSpanAttributes(attributes, owner) {
6726
+ if (Object.keys(attributes).length === 0) return void 0;
6727
+ const frame = makeAttributeFrame(attributes, owner);
6728
+ try {
6729
+ attributeStorage().push(frame);
6730
+ } catch (e) {
6731
+ return void 0;
6732
+ }
6733
+ return frame;
6734
+ }
6735
+ function unbindSpanAttributes(frame) {
6736
+ if (!frame || !isAttributeFrame(frame)) return;
6737
+ try {
6738
+ attributeStorage().remove(frame);
6739
+ } catch (e) {
6740
+ }
6741
+ }
6742
+ function applySpanAttributeFrames(span, setAttribute) {
6743
+ try {
6744
+ for (const frame of attributeStorage().getStack()) {
6745
+ if (!frame.isLive()) continue;
6746
+ frame.claimSpan(span);
6747
+ for (const [key, value] of Object.entries(frame.attributes)) {
6748
+ setAttribute(key, value);
6749
+ }
6750
+ }
6751
+ } catch (e) {
6752
+ }
6753
+ }
6754
+ function claimSpanForFrames(span) {
6755
+ try {
6756
+ for (const frame of attributeStorage().getStack()) {
6757
+ if (frame.isLive()) frame.claimSpan(span);
6758
+ }
6759
+ } catch (e) {
6760
+ }
6761
+ }
6762
+ function currentSpanAttributes() {
6763
+ const merged = {};
6764
+ try {
6765
+ for (const frame of attributeStorage().getStack()) {
6766
+ if (!frame.isLive()) continue;
6767
+ Object.assign(merged, frame.attributes);
6768
+ }
6769
+ } catch (e) {
6770
+ }
6771
+ return merged;
6772
+ }
6773
+ function markErrorSpanSeen(span) {
6774
+ try {
6775
+ for (const frame of attributeStorage().getStack()) {
6776
+ if (frame.ownsSpan(span)) frame.markErrorSpanSeen();
6777
+ }
6778
+ } catch (e) {
6779
+ }
6780
+ }
6781
+ function isAttributeFrame(value) {
6782
+ return typeof value.isLive === "function";
6783
+ }
6341
6784
 
6342
6785
  // ../core/dist/index.node.js
6343
6786
  var import_async_hooks = require("async_hooks");
@@ -10477,7 +10920,7 @@ var SignalEventSchema = external_exports.object({
10477
10920
  // package.json
10478
10921
  var package_default = {
10479
10922
  name: "raindrop-ai",
10480
- version: "0.2.4",
10923
+ version: "0.3.0",
10481
10924
  main: "dist/index.js",
10482
10925
  module: "dist/index.mjs",
10483
10926
  types: "dist/index.d.ts",
@@ -10680,7 +11123,7 @@ function redactPII(event) {
10680
11123
  }
10681
11124
 
10682
11125
  // src/tracing/tracer-core.ts
10683
- var import_api4 = require("@opentelemetry/api");
11126
+ var import_api5 = require("@opentelemetry/api");
10684
11127
  var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
10685
11128
  var import_instrumentation_anthropic = require("@traceloop/instrumentation-anthropic");
10686
11129
  var import_instrumentation_bedrock = require("@traceloop/instrumentation-bedrock");
@@ -10787,12 +11230,12 @@ async function postJson2(url, body, headers, opts) {
10787
11230
  }
10788
11231
 
10789
11232
  // src/tracing/direct/ids.ts
10790
- function getCrypto() {
11233
+ function getCrypto2() {
10791
11234
  const c = globalThis.crypto;
10792
11235
  return c;
10793
11236
  }
10794
11237
  function randomBytes2(length) {
10795
- const cryptoObj = getCrypto();
11238
+ const cryptoObj = getCrypto2();
10796
11239
  const out = new Uint8Array(length);
10797
11240
  if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
10798
11241
  cryptoObj.getRandomValues(out);
@@ -10830,7 +11273,7 @@ function base64Encode2(bytes) {
10830
11273
  }
10831
11274
  return out;
10832
11275
  }
10833
- function base64ToHex(base64) {
11276
+ function base64ToHex2(base64) {
10834
11277
  const maybeBuffer = globalThis.Buffer;
10835
11278
  if (maybeBuffer) {
10836
11279
  return maybeBuffer.from(base64, "base64").toString("hex");
@@ -10931,6 +11374,7 @@ var PROJECT_ID_SPAN_ATTRIBUTE = "raindrop.project_id";
10931
11374
  var AUTH_HINT_SPAN_ATTRIBUTE = "raindrop.auth_hint";
10932
11375
  var EXPORT_SUCCESS = 0;
10933
11376
  var EXPORT_FAILED = 1;
11377
+ var SPAN_STATUS_ERROR = 2;
10934
11378
  function authHintForKey(writeKey) {
10935
11379
  if (!writeKey) return void 0;
10936
11380
  return (0, import_node_crypto.createHash)("sha256").update(writeKey, "utf8").digest("hex").slice(0, 8);
@@ -10993,16 +11437,29 @@ function stampSpan(span, projectId, authHint) {
10993
11437
  } catch (e) {
10994
11438
  }
10995
11439
  }
11440
+ function stampContextAttributes(span) {
11441
+ try {
11442
+ applySpanAttributeFrames(span, (key, value) => span.setAttribute(key, value));
11443
+ } catch (e) {
11444
+ }
11445
+ }
10996
11446
  var RaindropContextSpanProcessor = class {
10997
11447
  onStart(span) {
10998
11448
  try {
11449
+ stampContextAttributes(span);
10999
11450
  const bound = currentRoutingBinding();
11000
11451
  if (!bound) return;
11001
11452
  stampSpan(span, bound.projectId, bound.authHint);
11002
11453
  } catch (e) {
11003
11454
  }
11004
11455
  }
11005
- onEnd() {
11456
+ onEnd(span) {
11457
+ var _a;
11458
+ try {
11459
+ if (((_a = span == null ? void 0 : span.status) == null ? void 0 : _a.code) !== SPAN_STATUS_ERROR) return;
11460
+ markErrorSpanSeen(span);
11461
+ } catch (e) {
11462
+ }
11006
11463
  }
11007
11464
  async forceFlush() {
11008
11465
  }
@@ -11181,9 +11638,18 @@ var DirectTraceShipper = class {
11181
11638
  attrString2(`traceloop.association.properties.${key}`, serializeAssociationValue(value))
11182
11639
  );
11183
11640
  }
11641
+ const spanIdentity = { spanIdB64 };
11642
+ claimSpanForFrames(spanIdentity);
11643
+ for (const [key, value] of Object.entries({
11644
+ ...currentSpanAttributes(),
11645
+ ...params.attributes
11646
+ })) {
11647
+ attributes.push(attrString2(key, value));
11648
+ }
11184
11649
  let status;
11185
11650
  if (params.error) {
11186
11651
  status = { code: 2, message: params.error };
11652
+ markErrorSpanSeen(spanIdentity);
11187
11653
  } else {
11188
11654
  status = {
11189
11655
  code: 1
@@ -11332,18 +11798,305 @@ var DirectTraceShipper = class {
11332
11798
  };
11333
11799
 
11334
11800
  // src/tracing/liveInteraction.ts
11335
- var import_api2 = require("@opentelemetry/api");
11801
+ var import_api3 = require("@opentelemetry/api");
11336
11802
  var traceloop = __toESM(require("@traceloop/node-server-sdk"));
11337
- function getPropertiesFromContext(context5) {
11803
+
11804
+ // src/tracing/subagents.ts
11805
+ var import_api2 = require("@opentelemetry/api");
11806
+ var DEFAULT_SUBAGENT_NAME = "subagent";
11807
+ var DISPATCH_ACCEPTED = "accepted";
11808
+ function reasonText(reason) {
11809
+ var _a;
11810
+ if (reason instanceof Error) return `${reason.name}: ${reason.message}`;
11811
+ if (typeof reason === "string") return reason;
11812
+ if (reason === void 0 || reason === null) return "";
11813
+ try {
11814
+ return (_a = JSON.stringify(reason)) != null ? _a : String(reason);
11815
+ } catch (e) {
11816
+ return String(reason);
11817
+ }
11818
+ }
11819
+ function stampCurrentSpan(attributes) {
11820
+ try {
11821
+ const span = import_api2.trace.getSpan(import_api2.context.active());
11822
+ if (!(span == null ? void 0 : span.isRecording())) return;
11823
+ for (const [key, value] of Object.entries(attributes)) {
11824
+ span.setAttribute(key, value);
11825
+ }
11826
+ } catch (e) {
11827
+ }
11828
+ }
11829
+ function stampOwnSpan(attributes, frame) {
11830
+ if (!frame) return;
11831
+ try {
11832
+ const span = import_api2.trace.getSpan(import_api2.context.active());
11833
+ if (!(span == null ? void 0 : span.isRecording()) || !frame.ownsSpan(span)) return;
11834
+ for (const [key, value] of Object.entries(attributes)) {
11835
+ span.setAttribute(key, value);
11836
+ }
11837
+ } catch (e) {
11838
+ }
11839
+ }
11840
+ function failOwnSpan(reason, frame) {
11841
+ try {
11842
+ const span = import_api2.trace.getSpan(import_api2.context.active());
11843
+ if (!(span == null ? void 0 : span.isRecording())) return false;
11844
+ if (!(frame == null ? void 0 : frame.ownsSpan(span))) return false;
11845
+ const message = reasonText(reason);
11846
+ span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message });
11847
+ span.recordException(reason instanceof Error ? reason : new Error(message));
11848
+ return true;
11849
+ } catch (e) {
11850
+ return false;
11851
+ }
11852
+ }
11853
+ function allowToolEvents(interaction) {
11854
+ const attributes = withMetadataPrefix(toolEventsAllowMetadata());
11855
+ interaction.bindToolEventsOptIn(attributes);
11856
+ stampCurrentSpan(attributes);
11857
+ }
11858
+ function recordSubagentDispatch(interaction, options) {
11859
+ var _a;
11860
+ const childEventId = options.childEventId || randomUUID();
11861
+ const name = options.name || DEFAULT_SUBAGENT_NAME;
11862
+ const parentEventId = (_a = interaction.getEventId()) != null ? _a : "";
11863
+ let traceIdHex;
11864
+ let dispatchSpanId;
11865
+ try {
11866
+ allowToolEvents(interaction);
11867
+ const recorded = interaction.recordDispatchSpan({
11868
+ name: options.toolName || DEFAULT_DISPATCH_SPAN_NAME,
11869
+ input: options.input,
11870
+ // A launch's "result" is the job handle; the answer belongs to the
11871
+ // child's event and never appears here.
11872
+ output: { jobId: childEventId, status: DISPATCH_ACCEPTED },
11873
+ properties: options.properties,
11874
+ attributes: detachedDispatchMetadata({ childEventId, name })
11875
+ });
11876
+ traceIdHex = recorded.traceIdHex;
11877
+ dispatchSpanId = recorded.spanIdHex;
11878
+ if (!dispatchSpanId) {
11879
+ console.warn(
11880
+ `[raindrop] subagent(${name}): no dispatch span was recorded, so event ${parentEventId} will not show the launch and NO carrier is returned \u2014 there is no span for the child to reference. Pass childEventId (${childEventId}) to the worker yourself if it must still report under that id. Tracing must be enabled for dispatches to be recorded.`
11881
+ );
11882
+ }
11883
+ } catch (error) {
11884
+ console.warn(
11885
+ `[raindrop] subagent(${name}) failed to record the dispatch; returning a carrier so the child still links back.`,
11886
+ error instanceof Error ? error.message : error
11887
+ );
11888
+ }
11889
+ if (!traceIdHex || !dispatchSpanId) {
11890
+ return {
11891
+ childEventId,
11892
+ name,
11893
+ parentEventId,
11894
+ dispatchSpanId: void 0,
11895
+ carrier: null,
11896
+ headers: {},
11897
+ langsmithHeaders: {}
11898
+ };
11899
+ }
11900
+ const carrier = {
11901
+ traceId: traceIdHex,
11902
+ spanId: dispatchSpanId,
11903
+ eventId: parentEventId,
11904
+ childEventId,
11905
+ name,
11906
+ ...interaction.getConvoId() ? { convoId: interaction.getConvoId() } : {},
11907
+ ...interaction.getUserId() ? { userId: interaction.getUserId() } : {}
11908
+ };
11909
+ return {
11910
+ childEventId,
11911
+ name,
11912
+ parentEventId,
11913
+ dispatchSpanId,
11914
+ carrier,
11915
+ headers: toHeaders(carrier),
11916
+ langsmithHeaders: toLangSmithHeaders(carrier)
11917
+ };
11918
+ }
11919
+ function carrierFirst(local, carried, field) {
11920
+ if (carried && local && local !== carried) {
11921
+ console.warn(
11922
+ `[raindrop] resumeSubagent: ignoring ${field}="${local}" in favor of the launcher's "${carried}" from the carrier; the launcher allocated it, and a child that substitutes its own breaks the link back to it.`
11923
+ );
11924
+ }
11925
+ return carried || local;
11926
+ }
11927
+ function isTraceCarrier(value) {
11928
+ const candidate = value;
11929
+ return typeof candidate.traceId === "string" && typeof candidate.spanId === "string" && typeof candidate.eventId === "string";
11930
+ }
11931
+ function readCarrier(carrierOrHeaders) {
11932
+ if (!carrierOrHeaders) return null;
11933
+ try {
11934
+ if (isTraceCarrier(carrierOrHeaders)) return carrierOrHeaders;
11935
+ return fromHeaders(carrierOrHeaders);
11936
+ } catch (error) {
11937
+ console.warn(
11938
+ `[raindrop] resumeSubagent: ignoring an unreadable hand-off carrier; the run reports as an unlinked event.`,
11939
+ error instanceof Error ? error.message : error
11940
+ );
11941
+ return null;
11942
+ }
11943
+ }
11944
+ function resolveSubagentResume(carrierOrHeaders, options = {}) {
11945
+ const parentStated = options.parent !== void 0;
11946
+ const parent = parentStated ? options.parent : readCarrier(carrierOrHeaders);
11947
+ if (!parentStated) warnUnresolvedCarrier(carrierOrHeaders, parent);
11948
+ const name = carrierFirst(options.name, parent == null ? void 0 : parent.name, "name") || DEFAULT_SUBAGENT_NAME;
11949
+ const eventId = carrierFirst(options.eventId, parent == null ? void 0 : parent.childEventId, "eventId") || randomUUID();
11950
+ const userId = carrierFirst(options.userId, parent == null ? void 0 : parent.userId, "userId") || "";
11951
+ const convoId = carrierFirst(options.convoId, parent == null ? void 0 : parent.convoId, "convoId");
11952
+ const link = parent ? {
11953
+ parentEventId: parent.eventId,
11954
+ ...parent.spanId ? { parentSpanId: parent.spanId } : {},
11955
+ name
11956
+ } : null;
11957
+ return {
11958
+ parent,
11959
+ link,
11960
+ name,
11961
+ eventId,
11962
+ event: options.event || `subagent.${name}`,
11963
+ userId,
11964
+ ...convoId ? { convoId } : {}
11965
+ };
11966
+ }
11967
+ function bindSubagentLink(link, owner) {
11968
+ if (!link) return void 0;
11969
+ return bindSpanAttributes(detachedChildMetadata(link), owner);
11970
+ }
11971
+ var LiveSubagentRun = class {
11972
+ constructor(params) {
11973
+ this.settled = false;
11974
+ this.interaction = params.interaction;
11975
+ this.eventId = params.eventId;
11976
+ this.name = params.name;
11977
+ this.convoId = params.convoId;
11978
+ this.parent = params.parent;
11979
+ this.frame = params.frame;
11980
+ this.frameOwner = params.frameOwner;
11981
+ }
11982
+ get linked() {
11983
+ return this.parent !== null;
11984
+ }
11985
+ async finish(result) {
11986
+ await this.close(result);
11987
+ }
11988
+ async fail(reason) {
11989
+ await this.abort(reason);
11990
+ }
11991
+ async cancel(reason) {
11992
+ const text = reason === void 0 ? "cancelled by caller" : reasonText(reason);
11993
+ const cancelled = cancelledTerminalAttributes();
11994
+ stampOwnSpan(cancelled, this.frame);
11995
+ await this.close({
11996
+ output: `Cancelled: ${text}`,
11997
+ // The caller's view of the child is its EVENT, not its spans, so the
11998
+ // marker has to be a property of the event as well.
11999
+ properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED }
12000
+ });
12001
+ }
12002
+ /**
12003
+ * Close the run with an abort reason, having first made sure the failure is
12004
+ * visible on a span.
12005
+ *
12006
+ * A failure has to leave an errored span behind or it is derived as finished.
12007
+ * Mark whatever is open; if nothing is and the child has not errored a span
12008
+ * already, record one — the killed-before-it-reached-the-model case, which is
12009
+ * much of what aborting is.
12010
+ */
12011
+ async abort(reason) {
12012
+ var _a, _b, _c;
12013
+ const text = reasonText(reason);
12014
+ if (!this.settled && !failOwnSpan(reason, this.frame)) {
12015
+ if (!((_a = this.frame) == null ? void 0 : _a.sawErrorSpan())) {
12016
+ this.interaction.recordSubagentAbortSpan({
12017
+ reason,
12018
+ message: text,
12019
+ attributes: {
12020
+ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: this.name,
12021
+ // The name explicitly, not only via the frame: an UNLINKED run has
12022
+ // no frame, and since the span is named for the operation
12023
+ // (`ai.subagent.failed`) rather than the sub-agent, this attribute
12024
+ // is the only thing left that says which sub-agent failed.
12025
+ ...(_c = (_b = this.frame) == null ? void 0 : _b.attributes) != null ? _c : {}
12026
+ }
12027
+ });
12028
+ }
12029
+ }
12030
+ await this.close({ output: text ? `Aborted: ${text}` : "Aborted before producing a result." });
12031
+ }
12032
+ async close(result) {
12033
+ if (this.settled) return;
12034
+ this.settled = true;
12035
+ try {
12036
+ await this.interaction.finish({ ...result, eventId: this.eventId });
12037
+ } finally {
12038
+ unbindSpanAttributes(this.frame);
12039
+ this.frame = void 0;
12040
+ this.frameOwner = void 0;
12041
+ }
12042
+ }
12043
+ /**
12044
+ * Run `fn` and guarantee the run reports an outcome, mirroring the Python
12045
+ * SDK's `with rd.resume_subagent(...) as run:`.
12046
+ *
12047
+ * A run that leaves without reporting output is closed with its abort reason.
12048
+ * That is not cosmetic: an event is created only from a run with non-empty
12049
+ * output, so a child that dies silently produces no event at all and the
12050
+ * caller's launch stays `queued` forever — indistinguishable from a job that
12051
+ * never started.
12052
+ */
12053
+ async use(fn) {
12054
+ try {
12055
+ const result = await fn(this);
12056
+ if (!this.settled) {
12057
+ console.warn(
12058
+ `[raindrop] sub-agent run ${this.eventId} (${this.name}) ended without reporting output; closing it with an abort reason. An event needs non-empty output to exist, so a silent child leaves its launcher showing "queued" forever \u2014 call finish({ output }), fail(reason) or cancel() before returning.`
12059
+ );
12060
+ await this.abortQuietly("sub-agent ended without reporting output");
12061
+ }
12062
+ return result;
12063
+ } catch (error) {
12064
+ await this.abortQuietly(error);
12065
+ throw error;
12066
+ }
12067
+ }
12068
+ /**
12069
+ * {@link abort} for the outcomes this class reports on the caller's behalf.
12070
+ *
12071
+ * `abort()` ends in `interaction.finish()`, which awaits the terminal event
12072
+ * POST and rejects when it fails. An explicit `fail()` may surface that — the
12073
+ * caller awaited it — but an implicit one must not: rejecting on the error
12074
+ * path replaces the caller's exception with a telemetry one, and rejecting on
12075
+ * the success path loses a result `fn` already produced.
12076
+ */
12077
+ async abortQuietly(reason) {
12078
+ try {
12079
+ await this.abort(reason);
12080
+ } catch (error) {
12081
+ console.warn(
12082
+ `[raindrop] sub-agent run ${this.eventId} (${this.name}) could not report its outcome; the run itself is unaffected.`,
12083
+ error instanceof Error ? error.message : error
12084
+ );
12085
+ }
12086
+ }
12087
+ };
12088
+
12089
+ // src/tracing/liveInteraction.ts
12090
+ function getPropertiesFromContext(context6) {
11338
12091
  const properties = {
11339
- ...context5.userId && { user_id: context5.userId },
11340
- ...context5.convoId && { convo_id: context5.convoId },
11341
- ...context5.eventId && { event_id: context5.eventId },
11342
- ...context5.event && { event_name: context5.event },
11343
- ...context5.properties || {}
12092
+ ...context6.userId && { user_id: context6.userId },
12093
+ ...context6.convoId && { convo_id: context6.convoId },
12094
+ ...context6.eventId && { event_id: context6.eventId },
12095
+ ...context6.event && { event_name: context6.event },
12096
+ ...context6.properties || {}
11344
12097
  };
11345
- if (context5.attachments && context5.attachments.length > 0) {
11346
- properties.attachments = stringifyBounded(context5.attachments);
12098
+ if (context6.attachments && context6.attachments.length > 0) {
12099
+ properties.attachments = stringifyBounded(context6.attachments);
11347
12100
  }
11348
12101
  return properties;
11349
12102
  }
@@ -11363,12 +12116,12 @@ function serializeAssociationProperties(properties) {
11363
12116
  function serializeSpanValue(value) {
11364
12117
  return stringifyBounded(value);
11365
12118
  }
11366
- function getLocalDebuggerMetadata(context5) {
12119
+ function getLocalDebuggerMetadata(context6) {
11367
12120
  return {
11368
- ...context5.eventId ? { eventId: context5.eventId } : {},
11369
- ...context5.event ? { eventName: context5.event } : {},
11370
- ...context5.userId ? { userId: context5.userId } : {},
11371
- ...context5.convoId ? { convoId: context5.convoId } : {}
12121
+ ...context6.eventId ? { eventId: context6.eventId } : {},
12122
+ ...context6.event ? { eventName: context6.event } : {},
12123
+ ...context6.userId ? { userId: context6.userId } : {},
12124
+ ...context6.convoId ? { convoId: context6.convoId } : {}
11372
12125
  };
11373
12126
  }
11374
12127
  var LiveToolSpan = class {
@@ -11380,7 +12133,7 @@ var LiveToolSpan = class {
11380
12133
  }
11381
12134
  spanIdHex() {
11382
12135
  const ctx = this.span.spanContext();
11383
- return (0, import_api2.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
12136
+ return (0, import_api3.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
11384
12137
  }
11385
12138
  setInput(input) {
11386
12139
  this.span.setAttribute("traceloop.entity.input", serializeSpanValue(input));
@@ -11392,13 +12145,13 @@ var LiveToolSpan = class {
11392
12145
  setError(error) {
11393
12146
  this.hasError = true;
11394
12147
  this.errorMessage = error instanceof Error ? error.message : String(error);
11395
- this.span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message: this.errorMessage });
12148
+ this.span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: this.errorMessage });
11396
12149
  this.span.recordException(error instanceof Error ? error : new Error(this.errorMessage));
11397
12150
  }
11398
12151
  end() {
11399
12152
  var _a;
11400
12153
  if (!this.hasError) {
11401
- this.span.setStatus({ code: import_api2.SpanStatusCode.OK });
12154
+ this.span.setStatus({ code: import_api3.SpanStatusCode.OK });
11402
12155
  }
11403
12156
  this.span.end();
11404
12157
  (_a = this.emitLiveEvent) == null ? void 0 : _a.call(this, {
@@ -11469,10 +12222,10 @@ var DirectToolSpan = class {
11469
12222
  }
11470
12223
  };
11471
12224
  var LiveInteraction = class {
11472
- constructor(context5, traceId, analytics, directShipper, routing) {
11473
- this.context = context5;
12225
+ constructor(context6, traceId, analytics, directShipper, routing) {
12226
+ this.context = context6;
11474
12227
  this.analytics = analytics;
11475
- this.tracer = import_api2.trace.getTracer("traceloop.tracer");
12228
+ this.tracer = import_api3.trace.getTracer("traceloop.tracer");
11476
12229
  this.traceId = traceId;
11477
12230
  this.directShipper = directShipper;
11478
12231
  this.routing = routing;
@@ -11507,7 +12260,7 @@ var LiveInteraction = class {
11507
12260
  this.traceId = explicitTraceId;
11508
12261
  return explicitTraceId;
11509
12262
  }
11510
- const activeSpan = import_api2.trace.getSpan(import_api2.context.active());
12263
+ const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
11511
12264
  const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
11512
12265
  if (activeTraceId) {
11513
12266
  this.traceId = activeTraceId;
@@ -11550,17 +12303,17 @@ var LiveInteraction = class {
11550
12303
  const spanIdB64 = base64Encode2(randomBytes2(8));
11551
12304
  const startTimeMs = Date.now();
11552
12305
  const spanContext = {
11553
- traceId: base64ToHex(traceIdB64),
11554
- spanId: base64ToHex(spanIdB64),
11555
- traceFlags: import_api2.TraceFlags.SAMPLED
12306
+ traceId: base64ToHex2(traceIdB64),
12307
+ spanId: base64ToHex2(spanIdB64),
12308
+ traceFlags: import_api3.TraceFlags.SAMPLED
11556
12309
  };
11557
- const wrappedContext = import_api2.trace.setSpan(
11558
- import_api2.context.active(),
11559
- import_api2.trace.wrapSpanContext(spanContext)
12310
+ const wrappedContext = import_api3.trace.setSpan(
12311
+ import_api3.context.active(),
12312
+ import_api3.trace.wrapSpanContext(spanContext)
11560
12313
  );
11561
12314
  const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
11562
12315
  try {
11563
- const result = await import_api2.context.with(wrappedContext, invoke);
12316
+ const result = await import_api3.context.with(wrappedContext, invoke);
11564
12317
  const endTimeMs = Date.now();
11565
12318
  this.directShipper.sendSpan({
11566
12319
  name: taskName,
@@ -11595,7 +12348,7 @@ var LiveInteraction = class {
11595
12348
  }
11596
12349
  }
11597
12350
  const wrappedFn = (...fnArgs) => {
11598
- const activeSpan = import_api2.trace.getSpan(import_api2.context.active());
12351
+ const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
11599
12352
  const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
11600
12353
  if (activeTraceId) {
11601
12354
  this.traceId = activeTraceId;
@@ -11645,19 +12398,19 @@ var LiveInteraction = class {
11645
12398
  metadata: params.inputParameters ? { args: params.inputParameters } : void 0
11646
12399
  });
11647
12400
  const spanContext = {
11648
- traceId: base64ToHex(traceIdB64),
11649
- spanId: base64ToHex(spanIdB64),
11650
- traceFlags: import_api2.TraceFlags.SAMPLED
12401
+ traceId: base64ToHex2(traceIdB64),
12402
+ spanId: base64ToHex2(spanIdB64),
12403
+ traceFlags: import_api3.TraceFlags.SAMPLED
11651
12404
  };
11652
- const wrappedContext = import_api2.trace.setSpan(
11653
- import_api2.context.active(),
11654
- import_api2.trace.wrapSpanContext(spanContext)
12405
+ const wrappedContext = import_api3.trace.setSpan(
12406
+ import_api3.context.active(),
12407
+ import_api3.trace.wrapSpanContext(spanContext)
11655
12408
  );
11656
12409
  const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
11657
12410
  let result;
11658
12411
  let error;
11659
12412
  try {
11660
- result = await import_api2.context.with(wrappedContext, invoke);
12413
+ result = await import_api3.context.with(wrappedContext, invoke);
11661
12414
  } catch (err) {
11662
12415
  error = err instanceof Error ? err.message : String(err);
11663
12416
  const endTimeMs2 = Date.now();
@@ -11722,9 +12475,9 @@ var LiveInteraction = class {
11722
12475
  const inputParams = params.inputParameters ? [params.inputParameters] : void 0;
11723
12476
  const emitLive = (event) => this.emitLiveEvent(event);
11724
12477
  const wrapped = async (...wrappedArgs) => {
11725
- const activeSpan = import_api2.trace.getSpan(import_api2.context.active());
12478
+ const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
11726
12479
  const ctx = activeSpan == null ? void 0 : activeSpan.spanContext();
11727
- const liveSpanId = ctx && (0, import_api2.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
12480
+ const liveSpanId = ctx && (0, import_api3.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
11728
12481
  if (activeSpan) {
11729
12482
  this.stampRouting(activeSpan);
11730
12483
  }
@@ -11832,7 +12585,7 @@ var LiveInteraction = class {
11832
12585
  console.log(`[raindrop] startToolSpan: started tool span "${name}"`);
11833
12586
  }
11834
12587
  const startSpanCtx = span.spanContext();
11835
- const startSpanIdHex = (0, import_api2.isValidSpanId)(startSpanCtx.spanId) ? startSpanCtx.spanId : void 0;
12588
+ const startSpanIdHex = (0, import_api3.isValidSpanId)(startSpanCtx.spanId) ? startSpanCtx.spanId : void 0;
11836
12589
  this.emitLiveEvent({
11837
12590
  type: "tool_start",
11838
12591
  spanId: startSpanIdHex,
@@ -11925,10 +12678,151 @@ var LiveInteraction = class {
11925
12678
  getEventId() {
11926
12679
  return this.context.eventId;
11927
12680
  }
12681
+ getUserId() {
12682
+ return this.context.userId;
12683
+ }
12684
+ getConvoId() {
12685
+ return this.context.convoId;
12686
+ }
12687
+ /**
12688
+ * Bind this turn's tool-call event opt-in, once.
12689
+ *
12690
+ * Owned by the interaction rather than by the execution context: the frame
12691
+ * lives exactly as long as the turn does (removed by `finish()`, and dead once
12692
+ * this interaction is collected), instead of outliving it on a context the
12693
+ * host may reuse for unrelated work.
12694
+ */
12695
+ bindToolEventsOptIn(attributes) {
12696
+ if (this.toolEventsFrame) return;
12697
+ this.toolEventsFrame = bindSpanAttributes(attributes, this);
12698
+ }
12699
+ subagent(options) {
12700
+ return recordSubagentDispatch(this, options);
12701
+ }
12702
+ /**
12703
+ * Record the tool span a detached dispatch is written on.
12704
+ *
12705
+ * Distinct from {@link startToolSpan} in the two ways the hand-off needs:
12706
+ * the contract's keys are set as RAW span attributes (under the
12707
+ * `traceloop.association.properties.` prefix the backend's reader cannot see
12708
+ * them), and the caller needs the span's ids to build the carrier.
12709
+ *
12710
+ * @internal
12711
+ */
12712
+ recordDispatchSpan(params) {
12713
+ var _a;
12714
+ const properties = {
12715
+ ...getPropertiesFromContext(this.context),
12716
+ ...(_a = params.properties) != null ? _a : {}
12717
+ };
12718
+ const input = params.input !== void 0 ? serializeSpanValue(params.input) : void 0;
12719
+ const output = serializeSpanValue(params.output);
12720
+ if (this.directShipper) {
12721
+ const activeContext = getActiveTraceContext();
12722
+ const traceIdB64 = this.ensureTraceId(activeContext.traceIdB64);
12723
+ const spanIdB64 = base64Encode2(randomBytes2(8));
12724
+ const timeMs = Date.now();
12725
+ this.directShipper.sendToolSpan({
12726
+ name: params.name,
12727
+ spanId: spanIdB64,
12728
+ input,
12729
+ output,
12730
+ durationMs: 0,
12731
+ startTimeMs: timeMs,
12732
+ endTimeMs: timeMs,
12733
+ properties,
12734
+ traceId: traceIdB64,
12735
+ parentSpanId: activeContext.parentSpanIdB64,
12736
+ attributes: params.attributes
12737
+ });
12738
+ this.emitLiveEvent({
12739
+ traceId: traceIdB64,
12740
+ spanId: spanIdB64,
12741
+ type: "tool_result",
12742
+ content: params.name,
12743
+ timestamp: timeMs,
12744
+ metadata: { result: params.output }
12745
+ });
12746
+ return { traceIdHex: base64ToHex2(traceIdB64), spanIdHex: base64ToHex2(spanIdB64) };
12747
+ }
12748
+ const span = this.tracer.startSpan(params.name);
12749
+ setAssociationProperties(span, properties);
12750
+ span.setAttribute("traceloop.span.kind", "tool");
12751
+ this.stampRouting(span);
12752
+ for (const [key, value] of Object.entries(params.attributes)) {
12753
+ span.setAttribute(key, value);
12754
+ }
12755
+ if (input !== void 0) {
12756
+ span.setAttribute("traceloop.entity.input", input);
12757
+ }
12758
+ span.setAttribute("traceloop.entity.output", output);
12759
+ span.setStatus({ code: import_api3.SpanStatusCode.OK });
12760
+ const spanContext = span.spanContext();
12761
+ span.end();
12762
+ this.emitLiveEvent({
12763
+ spanId: (0, import_api3.isValidSpanId)(spanContext.spanId) ? spanContext.spanId : void 0,
12764
+ type: "tool_result",
12765
+ content: params.name,
12766
+ timestamp: Date.now(),
12767
+ metadata: { result: params.output }
12768
+ });
12769
+ return {
12770
+ traceIdHex: (0, import_api3.isValidTraceId)(spanContext.traceId) ? spanContext.traceId : void 0,
12771
+ spanIdHex: (0, import_api3.isValidSpanId)(spanContext.spanId) ? spanContext.spanId : void 0
12772
+ };
12773
+ }
12774
+ /**
12775
+ * Record the errored span a detached sub-agent's failure needs when nothing
12776
+ * else is open.
12777
+ *
12778
+ * Frequently the child's ONLY span, so it carries the full reverse reference:
12779
+ * anything reading it alone still knows which launch it belongs to. Those
12780
+ * attributes come from the run's own frame rather than the ambient stack,
12781
+ * because `fail()` is often called from a different task than the one that
12782
+ * opened the run and this is the span that can least afford to lose the link.
12783
+ *
12784
+ * @internal
12785
+ */
12786
+ recordSubagentAbortSpan(params) {
12787
+ const { reason, message, attributes } = params;
12788
+ const properties = getPropertiesFromContext(this.context);
12789
+ if (this.directShipper) {
12790
+ const activeContext = getActiveTraceContext();
12791
+ const timeMs = Date.now();
12792
+ this.directShipper.sendSpan({
12793
+ name: SUBAGENT_ABORT_SPAN_NAME,
12794
+ // Not "tool": the run died, it did not call anything. `ai.operationId`
12795
+ // below is what keeps the span (see the attribute's docs in core).
12796
+ spanKind: "task",
12797
+ spanId: base64Encode2(randomBytes2(8)),
12798
+ durationMs: 0,
12799
+ startTimeMs: timeMs,
12800
+ endTimeMs: timeMs,
12801
+ error: message,
12802
+ properties,
12803
+ traceId: this.ensureTraceId(activeContext.traceIdB64),
12804
+ parentSpanId: activeContext.parentSpanIdB64,
12805
+ attributes: { ...attributes, [OPERATION_ID_ATTRIBUTE]: SUBAGENT_ABORT_OPERATION_ID }
12806
+ });
12807
+ return;
12808
+ }
12809
+ const span = this.tracer.startSpan(SUBAGENT_ABORT_SPAN_NAME);
12810
+ span.setAttribute(OPERATION_ID_ATTRIBUTE, SUBAGENT_ABORT_OPERATION_ID);
12811
+ setAssociationProperties(span, properties);
12812
+ this.stampRouting(span);
12813
+ for (const [key, value] of Object.entries(attributes)) {
12814
+ span.setAttribute(key, value);
12815
+ }
12816
+ span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
12817
+ span.recordException(reason instanceof Error ? reason : new Error(message));
12818
+ span.end();
12819
+ }
11928
12820
  async finish(resultEvent) {
11929
12821
  var _a, _b, _c, _d;
11930
12822
  unbindRoutingContext(this.boundContext);
11931
12823
  this.boundContext = void 0;
12824
+ unbindSpanAttributes(this.toolEventsFrame);
12825
+ this.toolEventsFrame = void 0;
11932
12826
  if (!this.traceId) {
11933
12827
  this.resolveLiveTraceId();
11934
12828
  }
@@ -12038,10 +12932,10 @@ var LiveInteraction = class {
12038
12932
  }
12039
12933
  if (error) {
12040
12934
  const errorMessage = error instanceof Error ? error.message : String(error);
12041
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message: errorMessage });
12935
+ span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: errorMessage });
12042
12936
  span.recordException(error instanceof Error ? error : new Error(errorMessage));
12043
12937
  } else {
12044
- span.setStatus({ code: import_api2.SpanStatusCode.OK });
12938
+ span.setStatus({ code: import_api3.SpanStatusCode.OK });
12045
12939
  }
12046
12940
  span.end(endTimeMs);
12047
12941
  if ((_c = this.analytics) == null ? void 0 : _c.debugLogs) {
@@ -12053,7 +12947,7 @@ var LiveInteraction = class {
12053
12947
  });
12054
12948
  }
12055
12949
  const trackToolCtx = span.spanContext();
12056
- const trackToolSpanIdHex = (0, import_api2.isValidSpanId)(trackToolCtx.spanId) ? trackToolCtx.spanId : void 0;
12950
+ const trackToolSpanIdHex = (0, import_api3.isValidSpanId)(trackToolCtx.spanId) ? trackToolCtx.spanId : void 0;
12057
12951
  this.emitLiveEvent({
12058
12952
  type: "tool_result",
12059
12953
  spanId: trackToolSpanIdHex,
@@ -12069,11 +12963,11 @@ var LiveInteraction = class {
12069
12963
  };
12070
12964
 
12071
12965
  // src/tracing/liveTracer.ts
12072
- var import_api3 = require("@opentelemetry/api");
12966
+ var import_api4 = require("@opentelemetry/api");
12073
12967
  var traceloop2 = __toESM(require("@traceloop/node-server-sdk"));
12074
12968
  var LiveTracer = class {
12075
12969
  constructor(globalProperties, directShipper, routing) {
12076
- this.tracer = import_api3.trace.getTracer("traceloop.tracer");
12970
+ this.tracer = import_api4.trace.getTracer("traceloop.tracer");
12077
12971
  this.globalProperties = globalProperties || {};
12078
12972
  this.directShipper = directShipper;
12079
12973
  this.routing = routing;
@@ -12085,7 +12979,7 @@ var LiveTracer = class {
12085
12979
  }
12086
12980
  emitLiveEvent(event) {
12087
12981
  var _a, _b;
12088
- const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
12982
+ const activeSpan = import_api4.trace.getSpan(import_api4.context.active());
12089
12983
  const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
12090
12984
  const active = getActiveTraceContext();
12091
12985
  const traceId = (_b = (_a = event.traceId) != null ? _a : activeTraceId) != null ? _b : active.traceIdB64;
@@ -12105,7 +12999,7 @@ var LiveTracer = class {
12105
12999
  };
12106
13000
  const inputParameters = typeof params === "string" ? void 0 : params.inputParameters;
12107
13001
  const wrappedFn = (...fnArgs) => {
12108
- const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
13002
+ const activeSpan = import_api4.trace.getSpan(import_api4.context.active());
12109
13003
  if (activeSpan) {
12110
13004
  this.stampRouting(activeSpan);
12111
13005
  }
@@ -12200,15 +13094,15 @@ var LiveTracer = class {
12200
13094
  }
12201
13095
  if (error) {
12202
13096
  const errorMessage = error instanceof Error ? error.message : String(error);
12203
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: errorMessage });
13097
+ span.setStatus({ code: import_api4.SpanStatusCode.ERROR, message: errorMessage });
12204
13098
  span.recordException(error instanceof Error ? error : new Error(errorMessage));
12205
13099
  } else {
12206
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
13100
+ span.setStatus({ code: import_api4.SpanStatusCode.OK });
12207
13101
  }
12208
13102
  span.end(endTimeMs);
12209
13103
  const ctx = span.spanContext();
12210
- const traceId = ctx.traceId || ((_b = import_api3.trace.getSpan(import_api3.context.active())) == null ? void 0 : _b.spanContext().traceId);
12211
- const spanIdHex = (0, import_api3.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
13104
+ const traceId = ctx.traceId || ((_b = import_api4.trace.getSpan(import_api4.context.active())) == null ? void 0 : _b.spanContext().traceId);
13105
+ const spanIdHex = (0, import_api4.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
12212
13106
  if (traceId) {
12213
13107
  this.emitLiveEvent({
12214
13108
  traceId,
@@ -12500,7 +13394,7 @@ try {
12500
13394
  e instanceof Error ? e.message : e
12501
13395
  );
12502
13396
  span.setStatus({
12503
- code: import_api4.SpanStatusCode.ERROR,
13397
+ code: import_api5.SpanStatusCode.ERROR,
12504
13398
  message: e instanceof Error ? e.message : String(e)
12505
13399
  });
12506
13400
  span.end();
@@ -12532,7 +13426,7 @@ try {
12532
13426
  );
12533
13427
  if (!spanEnded) {
12534
13428
  span.setStatus({
12535
- code: import_api4.SpanStatusCode.ERROR,
13429
+ code: import_api5.SpanStatusCode.ERROR,
12536
13430
  message: e instanceof Error ? e.message : String(e)
12537
13431
  });
12538
13432
  span.end();
@@ -12546,7 +13440,7 @@ try {
12546
13440
  } catch (error) {
12547
13441
  if (!spanEnded) {
12548
13442
  const msg = error instanceof Error ? error.message : String(error);
12549
- span.setStatus({ code: import_api4.SpanStatusCode.ERROR, message: msg });
13443
+ span.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: msg });
12550
13444
  span.recordException(error);
12551
13445
  span.end();
12552
13446
  spanEnded = true;
@@ -12569,7 +13463,7 @@ try {
12569
13463
  return result;
12570
13464
  }).catch((error) => {
12571
13465
  span.setStatus({
12572
- code: import_api4.SpanStatusCode.ERROR,
13466
+ code: import_api5.SpanStatusCode.ERROR,
12573
13467
  message: error.message
12574
13468
  });
12575
13469
  span.recordException(error);
@@ -12632,7 +13526,7 @@ function patchBedrockStreamingBug(inst) {
12632
13526
  } catch (error) {
12633
13527
  if (!spanEnded) {
12634
13528
  const msg = error instanceof Error ? error.message : String(error);
12635
- span.setStatus({ code: import_api4.SpanStatusCode.ERROR, message: msg });
13529
+ span.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: msg });
12636
13530
  span.recordException(error);
12637
13531
  span.end();
12638
13532
  spanEnded = true;
@@ -12655,7 +13549,7 @@ function patchBedrockStreamingBug(inst) {
12655
13549
  return result;
12656
13550
  }).catch((error) => {
12657
13551
  span.setStatus({
12658
- code: import_api4.SpanStatusCode.ERROR,
13552
+ code: import_api5.SpanStatusCode.ERROR,
12659
13553
  message: error.message
12660
13554
  });
12661
13555
  span.recordException(error);
@@ -12737,7 +13631,7 @@ function createManualInstrumentations(instrumentModules) {
12737
13631
  }
12738
13632
  function getCurrentTraceId() {
12739
13633
  var _a;
12740
- return (_a = import_api4.trace.getSpan(import_api4.context.active())) == null ? void 0 : _a.spanContext().traceId;
13634
+ return (_a = import_api5.trace.getSpan(import_api5.context.active())) == null ? void 0 : _a.spanContext().traceId;
12741
13635
  }
12742
13636
  var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
12743
13637
  var _a;
@@ -12930,6 +13824,72 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
12930
13824
  } catch (e) {
12931
13825
  }
12932
13826
  }) : void 0;
13827
+ const beginInteraction = (traceContext) => {
13828
+ var _a2;
13829
+ if (!traceContext.eventId) {
13830
+ traceContext.eventId = crypto.randomUUID();
13831
+ }
13832
+ const traceId = getCurrentTraceId();
13833
+ const interaction = new LiveInteraction(
13834
+ traceContext,
13835
+ traceId,
13836
+ analytics,
13837
+ directShipper,
13838
+ { projectId, authHint }
13839
+ );
13840
+ const bound = bindRoutingContext({ projectId, authHint }, interaction);
13841
+ interaction.setBoundContext(bound);
13842
+ try {
13843
+ analytics._trackAiPartial({
13844
+ ...traceContext,
13845
+ properties: {
13846
+ ...(_a2 = traceContext.properties) != null ? _a2 : {},
13847
+ ...interaction.getTraceId() ? { trace_id: interaction.getTraceId() } : {}
13848
+ }
13849
+ });
13850
+ if (interaction.getTraceId()) {
13851
+ activeInteractions.set(interaction.getTraceId(), interaction);
13852
+ }
13853
+ activeInteractionsByEventId.set(traceContext.eventId, interaction);
13854
+ } catch (error) {
13855
+ unbindRoutingContext(bound);
13856
+ throw error;
13857
+ }
13858
+ return interaction;
13859
+ };
13860
+ const openSubagentRun = (carrierOrHeaders, options2) => {
13861
+ const resolved = resolveSubagentResume(carrierOrHeaders, options2);
13862
+ if (!resolved.parent && isDebug) {
13863
+ console.log(
13864
+ `[raindrop] resumeSubagent(${resolved.name}): no hand-off carrier on the request; reporting as an unlinked event ${resolved.eventId}.`
13865
+ );
13866
+ }
13867
+ const frameOwner = { subagentEventId: resolved.eventId };
13868
+ const frame = bindSubagentLink(resolved.link, frameOwner);
13869
+ let interaction;
13870
+ try {
13871
+ interaction = beginInteraction({
13872
+ eventId: resolved.eventId,
13873
+ event: resolved.event,
13874
+ userId: resolved.userId,
13875
+ ...resolved.convoId ? { convoId: resolved.convoId } : {},
13876
+ ...options2.input !== void 0 ? { input: options2.input } : {},
13877
+ ...options2.model !== void 0 ? { model: options2.model } : {},
13878
+ ...options2.properties ? { properties: options2.properties } : {}
13879
+ });
13880
+ } catch (error) {
13881
+ unbindSpanAttributes(frame);
13882
+ throw error;
13883
+ }
13884
+ return new LiveSubagentRun({
13885
+ interaction,
13886
+ eventId: resolved.eventId,
13887
+ name: resolved.name,
13888
+ ...resolved.convoId ? { convoId: resolved.convoId } : {},
13889
+ parent: resolved.link,
13890
+ ...frame ? { frame, frameOwner } : {}
13891
+ });
13892
+ };
12933
13893
  return {
12934
13894
  /**
12935
13895
  * Returns instrumentation instances for your NodeSDK.
@@ -13039,37 +13999,13 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
13039
13999
  );
13040
14000
  },
13041
14001
  begin(traceContext) {
13042
- var _a2;
13043
- if (!traceContext.eventId) {
13044
- traceContext.eventId = crypto.randomUUID();
13045
- }
13046
- const traceId = getCurrentTraceId();
13047
- const interaction = new LiveInteraction(
13048
- traceContext,
13049
- traceId,
13050
- analytics,
13051
- directShipper,
13052
- { projectId, authHint }
13053
- );
13054
- const bound = bindRoutingContext({ projectId, authHint }, interaction);
13055
- interaction.setBoundContext(bound);
13056
- try {
13057
- analytics._trackAiPartial({
13058
- ...traceContext,
13059
- properties: {
13060
- ...(_a2 = traceContext.properties) != null ? _a2 : {},
13061
- ...interaction.getTraceId() ? { trace_id: interaction.getTraceId() } : {}
13062
- }
13063
- });
13064
- if (interaction.getTraceId()) {
13065
- activeInteractions.set(interaction.getTraceId(), interaction);
13066
- }
13067
- activeInteractionsByEventId.set(traceContext.eventId, interaction);
13068
- } catch (error) {
13069
- unbindRoutingContext(bound);
13070
- throw error;
13071
- }
13072
- return interaction;
14002
+ return beginInteraction(traceContext);
14003
+ },
14004
+ resumeSubagent(carrierOrHeaders, options2 = {}) {
14005
+ return openSubagentRun(carrierOrHeaders, options2);
14006
+ },
14007
+ withSubagentRun(carrierOrHeaders, fn, options2 = {}) {
14008
+ return openSubagentRun(carrierOrHeaders, options2).use(fn);
13073
14009
  },
13074
14010
  getActiveInteraction(eventId) {
13075
14011
  const interactionByEventId = activeInteractionsByEventId.get(eventId);
@@ -13476,6 +14412,65 @@ var Raindrop = class {
13476
14412
  resumeInteraction(eventId) {
13477
14413
  return this._tracing.getActiveInteraction(eventId);
13478
14414
  }
14415
+ /**
14416
+ * Opens the child's own event for a launched detached sub-agent.
14417
+ *
14418
+ * Sibling to {@link resumeInteraction}, and deliberately not the same thing:
14419
+ * a resumed interaction JOINS the caller's event, while a detached sub-agent
14420
+ * reports as its OWN event under the id the launcher minted, linked back only
14421
+ * by the hand-off attributes both sides write. Every span the run emits
14422
+ * carries the reverse reference until it reports a result.
14423
+ *
14424
+ * Pass the headers the request arrived with. A missing carrier is a
14425
+ * legitimate state — the sub-agent was invoked directly rather than
14426
+ * dispatched — so this always returns a usable run and leaves `parent` null;
14427
+ * call sites stay unconditional. A malformed carrier costs the link, never
14428
+ * the request.
14429
+ *
14430
+ * The carrier is authoritative for every identity field it supplies. The
14431
+ * options are fallbacks for the direct-invocation case, not overrides: each
14432
+ * field names something the launcher already recorded, so a locally minted
14433
+ * value winning would strand the child outside the link.
14434
+ *
14435
+ * > **Trust boundary.** A carrier names the event the child will be
14436
+ * > attributed to, so accepting one from an untrusted caller lets that caller
14437
+ * > write into another tenant's trace. Only read carriers that came from
14438
+ * > inside your own trust boundary.
14439
+ *
14440
+ * @example
14441
+ * ```typescript
14442
+ * const run = raindrop.resumeSubagent(request.headers);
14443
+ * try {
14444
+ * const answer = await doTheWork();
14445
+ * await run.finish({ output: answer });
14446
+ * } catch (error) {
14447
+ * await run.fail(error);
14448
+ * }
14449
+ * ```
14450
+ */
14451
+ resumeSubagent(headers, options) {
14452
+ return this._tracing.resumeSubagent(headers, options);
14453
+ }
14454
+ /**
14455
+ * Runs `fn` as a detached sub-agent and guarantees the run reports an
14456
+ * outcome, mirroring the Python SDK's `with rd.resume_subagent(...) as run:`.
14457
+ *
14458
+ * A run that returns without reporting output is closed with an abort reason,
14459
+ * and one that throws is failed with it. That is not cosmetic: an event is
14460
+ * created only from a run with non-empty output, so a child that dies
14461
+ * silently produces no event at all and its launcher stays on `queued`
14462
+ * forever — indistinguishable from a job that never started.
14463
+ *
14464
+ * @example
14465
+ * ```typescript
14466
+ * await raindrop.withSubagentRun(request.headers, async (run) => {
14467
+ * await run.finish({ output: await doTheWork() });
14468
+ * });
14469
+ * ```
14470
+ */
14471
+ withSubagentRun(headers, fn, options) {
14472
+ return this._tracing.withSubagentRun(headers, fn, options);
14473
+ }
13479
14474
  /**
13480
14475
  * Creates a framework-agnostic self-diagnostics tool definition.
13481
14476
  *
@@ -13492,14 +14487,14 @@ var Raindrop = class {
13492
14487
  const description = buildSelfDiagnosticsDescription(signals, options.guidance);
13493
14488
  const inputSchema = buildSelfDiagnosticsInputSchema(signalKeys);
13494
14489
  const onMissingEventId = (_b = options.onMissingEventId) != null ? _b : "warn";
13495
- const execute = async (rawInput, context5) => {
14490
+ const execute = async (rawInput, context6) => {
13496
14491
  var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
13497
14492
  const input = isRecord(rawInput) ? rawInput : void 0;
13498
14493
  const fallbackCategory = (_a2 = signalKeys[0]) != null ? _a2 : "unknown";
13499
14494
  const categoryCandidate = normalizeEventId(input == null ? void 0 : input["category"]);
13500
14495
  const category = categoryCandidate && signalKeySet.has(categoryCandidate) ? categoryCandidate : fallbackCategory;
13501
14496
  const detail = (_b2 = normalizeEventId(input == null ? void 0 : input["detail"])) != null ? _b2 : "";
13502
- const eventId = (_l = (_k = (_i = (_g = (_f = (_e = (_d = normalizeEventId(context5 == null ? void 0 : context5.eventId)) != null ? _d : (_c = context5 == null ? void 0 : context5.interaction) == null ? void 0 : _c.getEventId()) != null ? _e : resolveEventIdFromMetadata(context5 == null ? void 0 : context5.metadata)) != null ? _f : normalizeEventId(input == null ? void 0 : input["event_id"])) != null ? _g : normalizeEventId(input == null ? void 0 : input["eventId"])) != null ? _i : (_h = options.interaction) == null ? void 0 : _h.getEventId()) != null ? _k : (_j = options.getEventId) == null ? void 0 : _j.call(options)) != null ? _l : normalizeEventId(options.eventId);
14497
+ const eventId = (_l = (_k = (_i = (_g = (_f = (_e = (_d = normalizeEventId(context6 == null ? void 0 : context6.eventId)) != null ? _d : (_c = context6 == null ? void 0 : context6.interaction) == null ? void 0 : _c.getEventId()) != null ? _e : resolveEventIdFromMetadata(context6 == null ? void 0 : context6.metadata)) != null ? _f : normalizeEventId(input == null ? void 0 : input["event_id"])) != null ? _g : normalizeEventId(input == null ? void 0 : input["eventId"])) != null ? _i : (_h = options.interaction) == null ? void 0 : _h.getEventId()) != null ? _k : (_j = options.getEventId) == null ? void 0 : _j.call(options)) != null ? _l : normalizeEventId(options.eventId);
13503
14498
  if (!eventId) {
13504
14499
  const message = "self diagnostics signal skipped: missing eventId. Pass eventId, interaction, or getEventId when creating or executing the tool.";
13505
14500
  if (onMissingEventId === "throw") {
@@ -13517,11 +14512,11 @@ var Raindrop = class {
13517
14512
  type: "agent",
13518
14513
  sentiment: signalDefinition == null ? void 0 : signalDefinition.sentiment,
13519
14514
  properties: {
13520
- source: (context5 == null ? void 0 : context5.source) || options.source || SELF_DIAGNOSTICS_SOURCE_DEFAULT,
14515
+ source: (context6 == null ? void 0 : context6.source) || options.source || SELF_DIAGNOSTICS_SOURCE_DEFAULT,
13521
14516
  category,
13522
14517
  signal_description: signalDefinition == null ? void 0 : signalDefinition.description,
13523
14518
  ...detail ? { detail } : {},
13524
- ...(_m = context5 == null ? void 0 : context5.properties) != null ? _m : {}
14519
+ ...(_m = context6 == null ? void 0 : context6.properties) != null ? _m : {}
13525
14520
  }
13526
14521
  });
13527
14522
  return { acknowledged: true, category, eventId };
@@ -13909,7 +14904,7 @@ var Raindrop = class {
13909
14904
  }
13910
14905
  getContext() {
13911
14906
  const runtime = detectRuntime();
13912
- const context5 = {
14907
+ const context6 = {
13913
14908
  library: {
13914
14909
  name: package_default.name,
13915
14910
  version: package_default.version
@@ -13919,9 +14914,9 @@ var Raindrop = class {
13919
14914
  }
13920
14915
  };
13921
14916
  if (runtime === "node") {
13922
- context5.metadata.nodeVersion = process.version;
14917
+ context6.metadata.nodeVersion = process.version;
13923
14918
  }
13924
- return context5;
14919
+ return context6;
13925
14920
  }
13926
14921
  formatZodError(error) {
13927
14922
  return error.issues.map((issue) => `(path: ${issue.path.join(".")}): ${issue.message}`).join(", ");