@friskai/frisk-js 0.3.0 → 0.3.1

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.
Files changed (32) hide show
  1. package/dist/adapters/langchain/frisk-callback-handler.d.ts +80 -3
  2. package/dist/adapters/langchain/frisk-callback-handler.d.ts.map +1 -1
  3. package/dist/adapters/langchain/index.js +556 -238
  4. package/dist/adapters/langchain/index.js.map +1 -453
  5. package/dist/core/frisk-session.d.ts +43 -10
  6. package/dist/core/frisk-session.d.ts.map +1 -1
  7. package/dist/core/llm-reasoning/extractLlmReasoning.d.ts +8 -0
  8. package/dist/core/llm-reasoning/extractLlmReasoning.d.ts.map +1 -0
  9. package/dist/core/spans/frisk-span.d.ts +38 -0
  10. package/dist/core/spans/frisk-span.d.ts.map +1 -0
  11. package/dist/core/spans/index.d.ts +7 -0
  12. package/dist/core/spans/index.d.ts.map +1 -0
  13. package/dist/core/spans/llm-call-span.d.ts +23 -0
  14. package/dist/core/spans/llm-call-span.d.ts.map +1 -0
  15. package/dist/core/spans/operation-span.d.ts +13 -0
  16. package/dist/core/spans/operation-span.d.ts.map +1 -0
  17. package/dist/core/spans/session-span.d.ts +20 -0
  18. package/dist/core/spans/session-span.d.ts.map +1 -0
  19. package/dist/core/spans/tool-call-decision-span.d.ts +27 -0
  20. package/dist/core/spans/tool-call-decision-span.d.ts.map +1 -0
  21. package/dist/core/spans/tool-call-observation-span.d.ts +28 -0
  22. package/dist/core/spans/tool-call-observation-span.d.ts.map +1 -0
  23. package/dist/generated/sdk-meta.d.ts +1 -1
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +318 -171
  27. package/dist/index.js.map +1 -439
  28. package/dist/telemetry/constants.d.ts +24 -0
  29. package/dist/telemetry/constants.d.ts.map +1 -1
  30. package/package.json +2 -1
  31. package/dist/core/tool-call-span.d.ts +0 -102
  32. package/dist/core/tool-call-span.d.ts.map +0 -1
@@ -31252,7 +31252,7 @@ var require_root2 = __commonJS((exports, module) => {
31252
31252
  return ScopeSpans;
31253
31253
  }();
31254
31254
  v12.Span = function() {
31255
- function Span2(properties) {
31255
+ function Span(properties) {
31256
31256
  this.attributes = [];
31257
31257
  this.events = [];
31258
31258
  this.links = [];
@@ -31262,26 +31262,26 @@ var require_root2 = __commonJS((exports, module) => {
31262
31262
  this[keys[i]] = properties[keys[i]];
31263
31263
  }
31264
31264
  }
31265
- Span2.prototype.traceId = null;
31266
- Span2.prototype.spanId = null;
31267
- Span2.prototype.traceState = null;
31268
- Span2.prototype.parentSpanId = null;
31269
- Span2.prototype.flags = null;
31270
- Span2.prototype.name = null;
31271
- Span2.prototype.kind = null;
31272
- Span2.prototype.startTimeUnixNano = null;
31273
- Span2.prototype.endTimeUnixNano = null;
31274
- Span2.prototype.attributes = $util.emptyArray;
31275
- Span2.prototype.droppedAttributesCount = null;
31276
- Span2.prototype.events = $util.emptyArray;
31277
- Span2.prototype.droppedEventsCount = null;
31278
- Span2.prototype.links = $util.emptyArray;
31279
- Span2.prototype.droppedLinksCount = null;
31280
- Span2.prototype.status = null;
31281
- Span2.create = function create(properties) {
31282
- return new Span2(properties);
31283
- };
31284
- Span2.encode = function encode2(message, writer) {
31265
+ Span.prototype.traceId = null;
31266
+ Span.prototype.spanId = null;
31267
+ Span.prototype.traceState = null;
31268
+ Span.prototype.parentSpanId = null;
31269
+ Span.prototype.flags = null;
31270
+ Span.prototype.name = null;
31271
+ Span.prototype.kind = null;
31272
+ Span.prototype.startTimeUnixNano = null;
31273
+ Span.prototype.endTimeUnixNano = null;
31274
+ Span.prototype.attributes = $util.emptyArray;
31275
+ Span.prototype.droppedAttributesCount = null;
31276
+ Span.prototype.events = $util.emptyArray;
31277
+ Span.prototype.droppedEventsCount = null;
31278
+ Span.prototype.links = $util.emptyArray;
31279
+ Span.prototype.droppedLinksCount = null;
31280
+ Span.prototype.status = null;
31281
+ Span.create = function create(properties) {
31282
+ return new Span(properties);
31283
+ };
31284
+ Span.encode = function encode2(message, writer) {
31285
31285
  if (!writer)
31286
31286
  writer = $Writer.create();
31287
31287
  if (message.traceId != null && Object.hasOwnProperty.call(message, "traceId"))
@@ -31321,10 +31321,10 @@ var require_root2 = __commonJS((exports, module) => {
31321
31321
  writer.uint32(133).fixed32(message.flags);
31322
31322
  return writer;
31323
31323
  };
31324
- Span2.encodeDelimited = function encodeDelimited(message, writer) {
31324
+ Span.encodeDelimited = function encodeDelimited(message, writer) {
31325
31325
  return this.encode(message, writer).ldelim();
31326
31326
  };
31327
- Span2.decode = function decode2(reader, length, error2) {
31327
+ Span.decode = function decode2(reader, length, error2) {
31328
31328
  if (!(reader instanceof $Reader))
31329
31329
  reader = $Reader.create(reader);
31330
31330
  var end = length === undefined ? reader.len : reader.pos + length, message = new $root.opentelemetry.proto.trace.v1.Span;
@@ -31410,12 +31410,12 @@ var require_root2 = __commonJS((exports, module) => {
31410
31410
  }
31411
31411
  return message;
31412
31412
  };
31413
- Span2.decodeDelimited = function decodeDelimited(reader) {
31413
+ Span.decodeDelimited = function decodeDelimited(reader) {
31414
31414
  if (!(reader instanceof $Reader))
31415
31415
  reader = new $Reader(reader);
31416
31416
  return this.decode(reader, reader.uint32());
31417
31417
  };
31418
- Span2.verify = function verify(message) {
31418
+ Span.verify = function verify(message) {
31419
31419
  if (typeof message !== "object" || message === null)
31420
31420
  return "object expected";
31421
31421
  if (message.traceId != null && message.hasOwnProperty("traceId")) {
@@ -31508,7 +31508,7 @@ var require_root2 = __commonJS((exports, module) => {
31508
31508
  }
31509
31509
  return null;
31510
31510
  };
31511
- Span2.fromObject = function fromObject(object2) {
31511
+ Span.fromObject = function fromObject(object2) {
31512
31512
  if (object2 instanceof $root.opentelemetry.proto.trace.v1.Span)
31513
31513
  return object2;
31514
31514
  var message = new $root.opentelemetry.proto.trace.v1.Span;
@@ -31631,7 +31631,7 @@ var require_root2 = __commonJS((exports, module) => {
31631
31631
  }
31632
31632
  return message;
31633
31633
  };
31634
- Span2.toObject = function toObject(message, options) {
31634
+ Span.toObject = function toObject(message, options) {
31635
31635
  if (!options)
31636
31636
  options = {};
31637
31637
  var object2 = {};
@@ -31730,16 +31730,16 @@ var require_root2 = __commonJS((exports, module) => {
31730
31730
  object2.flags = message.flags;
31731
31731
  return object2;
31732
31732
  };
31733
- Span2.prototype.toJSON = function toJSON() {
31733
+ Span.prototype.toJSON = function toJSON() {
31734
31734
  return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
31735
31735
  };
31736
- Span2.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
31736
+ Span.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
31737
31737
  if (typeUrlPrefix === undefined) {
31738
31738
  typeUrlPrefix = "type.googleapis.com";
31739
31739
  }
31740
31740
  return typeUrlPrefix + "/opentelemetry.proto.trace.v1.Span";
31741
31741
  };
31742
- Span2.SpanKind = function() {
31742
+ Span.SpanKind = function() {
31743
31743
  var valuesById = {}, values = Object.create(valuesById);
31744
31744
  values[valuesById[0] = "SPAN_KIND_UNSPECIFIED"] = 0;
31745
31745
  values[valuesById[1] = "SPAN_KIND_INTERNAL"] = 1;
@@ -31749,7 +31749,7 @@ var require_root2 = __commonJS((exports, module) => {
31749
31749
  values[valuesById[5] = "SPAN_KIND_CONSUMER"] = 5;
31750
31750
  return values;
31751
31751
  }();
31752
- Span2.Event = function() {
31752
+ Span.Event = function() {
31753
31753
  function Event(properties) {
31754
31754
  this.attributes = [];
31755
31755
  if (properties) {
@@ -31919,7 +31919,7 @@ var require_root2 = __commonJS((exports, module) => {
31919
31919
  };
31920
31920
  return Event;
31921
31921
  }();
31922
- Span2.Link = function() {
31922
+ Span.Link = function() {
31923
31923
  function Link(properties) {
31924
31924
  this.attributes = [];
31925
31925
  if (properties) {
@@ -32126,7 +32126,7 @@ var require_root2 = __commonJS((exports, module) => {
32126
32126
  };
32127
32127
  return Link;
32128
32128
  }();
32129
- return Span2;
32129
+ return Span;
32130
32130
  }();
32131
32131
  v12.Status = function() {
32132
32132
  function Status(properties) {
@@ -42935,7 +42935,7 @@ var require_Tracer = __commonJS((exports) => {
42935
42935
  var utility_1 = require_utility();
42936
42936
  var platform_1 = require_platform4();
42937
42937
 
42938
- class Tracer2 {
42938
+ class Tracer {
42939
42939
  _sampler;
42940
42940
  _generalLimits;
42941
42941
  _spanLimits;
@@ -43037,7 +43037,7 @@ var require_Tracer = __commonJS((exports) => {
43037
43037
  return this._spanLimits;
43038
43038
  }
43039
43039
  }
43040
- exports.Tracer = Tracer2;
43040
+ exports.Tracer = Tracer;
43041
43041
  });
43042
43042
 
43043
43043
  // ../../node_modules/@opentelemetry/sdk-trace-base/build/src/MultiSpanProcessor.js
@@ -43625,13 +43625,6 @@ class MissingToolPoliciesExtensionError extends FriskError {
43625
43625
  }
43626
43626
  }
43627
43627
 
43628
- class ToolCallSpanNotInitializedError extends Error {
43629
- constructor(message = "Tool call span has not been initialized. Call enter() first.") {
43630
- super(message);
43631
- this.name = "ToolCallSpanNotInitializedError";
43632
- }
43633
- }
43634
-
43635
43628
  // src/logging/console-logger.ts
43636
43629
  var LEVEL_PRIORITY = {
43637
43630
  error: 0,
@@ -43751,35 +43744,6 @@ function captureError(e, logger, meta) {
43751
43744
  logError(logger, e.message, e, meta);
43752
43745
  }
43753
43746
 
43754
- // src/telemetry/constants.ts
43755
- var TRACER_NAME = "frisk_js_sdk";
43756
- var TRACER_VERSION = "0.1.0";
43757
- var SPAN_NAME_DECIDE_TOOL_CALL = "frisk.tool_call.decide";
43758
- var SPAN_NAME_OBSERVE_TOOL_CALL = "frisk.tool_call.observation";
43759
- var SPAN_NAME_FRISK_SESSION = "frisk.session";
43760
- var ATTRIBUTE_NAME_SESSION_PROMPT = "frisk.session.prompt";
43761
- var ATTRIBUTE_NAME_SESSION_ID = "frisk.session.id";
43762
- var ATTRIBUTE_NAME_REMOTE_SESSION_ID = "frisk.session.remote_id";
43763
- var ATTRIBUTE_NAME_LLM_REASONING = "frisk.llm_reasoning";
43764
- var ATTRIBUTE_NAME_TOOL_NAME = "frisk.tool.name";
43765
- var ATTRIBUTE_NAME_FRISK_TOOL_ID = "frisk.tool.id";
43766
- var ATTRIBUTE_NAME_FRISK_TOOL_VERSION_ID = "frisk.tool.version_id";
43767
- var ATTRIBUTE_NAME_TOOL_CALL_ID = "frisk.tool_call.id";
43768
- var ATTRIBUTE_NAME_TOOL_ARGS_JSON = "frisk.tool.args.json";
43769
- var ATTRIBUTE_NAME_TOOL_ARGS_REDACTED_PATHS_JSON = "frisk.tool.args_redacted_paths.json";
43770
- var ATTRIBUTE_NAME_AGENT_STATE_JSON = "frisk.agent_state.json";
43771
- var ATTRIBUTE_NAME_AGENT_STATE_REDACTED_PATHS_JSON = "frisk.agent_state_redacted_paths.json";
43772
- var ATTRIBUTE_NAME_DECISION_MATCHED_RULE_COUNT = "frisk.decision.matched_rule_count";
43773
- var ATTRIBUTE_NAME_DECISION_OUTCOME = "frisk.decision.outcome";
43774
- var ATTRIBUTE_NAME_DECISION_REASON = "frisk.decision.reason";
43775
- var ATTRIBUTE_NAME_ERROR_TYPE = "error.type";
43776
- var ATTRIBUTE_NAME_ERROR_MESSAGE = "error.message";
43777
- var ATTRIBUTE_NAME_TOOL_CALL_IS_SUCCESS = "frisk.tool_call.is_success";
43778
- var ATTRIBUTE_NAME_TOOL_CALL_IS_ERROR = "frisk.tool_call.is_error";
43779
- var ATTRIBUTE_NAME_TOOL_CALL_COUNT = "frisk.tool_calls.count";
43780
- var ATTRIBUTE_NAME_TOOL_CALL_ERROR_COUNT = "frisk.tool_calls.error_count";
43781
- var ATTRIBUTE_NAME_TOOL_CALL_SEQUENCE_NUMBER = "frisk.tool_call.sequence_number";
43782
-
43783
43747
  // ../../node_modules/zod/v4/core/core.js
43784
43748
  var NEVER = Object.freeze({
43785
43749
  status: "aborted"
@@ -48171,6 +48135,18 @@ var llmReasoningZodShape = {
48171
48135
  [LLM_REASONING_ARG_NAME]: string2().describe(LLM_REASONING_ARG_DESCRIPTION)
48172
48136
  };
48173
48137
 
48138
+ // src/core/llm-reasoning/extractLlmReasoning.ts
48139
+ function extractLlmReasoning(toolArgs) {
48140
+ if (typeof toolArgs !== "object" || toolArgs === null || Array.isArray(toolArgs)) {
48141
+ return null;
48142
+ }
48143
+ const rawReasoning = toolArgs[LLM_REASONING_ARG_NAME];
48144
+ if (rawReasoning === null || rawReasoning === undefined) {
48145
+ return null;
48146
+ }
48147
+ return String(rawReasoning);
48148
+ }
48149
+
48174
48150
  // src/core/llm-reasoning/removeLlmReasoningArg.ts
48175
48151
  function removeLlmReasoningArg(input) {
48176
48152
  if (!(LLM_REASONING_ARG_NAME in input)) {
@@ -48216,136 +48192,226 @@ class SessionRegistry {
48216
48192
  }
48217
48193
  }
48218
48194
 
48219
- // src/core/tool-call-span.ts
48195
+ // src/core/spans/frisk-span.ts
48220
48196
  var import_api = __toESM(require_src(), 1);
48221
48197
 
48222
- // src/core/redaction-options.ts
48223
- function resolveRedactionOptions(options) {
48224
- return {
48225
- redactToolArgs: options?.redactToolArgs ?? false,
48226
- redactAgentState: options?.redactAgentState ?? false
48227
- };
48228
- }
48229
-
48230
- // src/core/tool-call-span.ts
48231
- class ToolCallSpan {
48232
- adapter;
48233
- toolCall;
48234
- friskToolId;
48235
- agentState;
48236
- parent;
48237
- tracer;
48238
- redaction;
48239
- _span = null;
48240
- _traceContextCarrier = null;
48241
- sessionId;
48242
- friskToolVersionId;
48198
+ class FriskSpan {
48199
+ _spanName;
48200
+ _attributeFields;
48201
+ _otelSpan;
48202
+ _attributes = {};
48203
+ _ended = false;
48243
48204
  constructor({
48244
- sessionId,
48245
- adapter,
48246
- toolCall,
48247
- friskToolId,
48248
- friskToolVersionId,
48249
- agentState,
48250
- parent,
48251
48205
  tracer,
48252
- redact
48206
+ parent,
48207
+ spanName,
48208
+ attributeFields
48253
48209
  }) {
48254
- this.sessionId = sessionId;
48255
- this.adapter = adapter;
48256
- this.toolCall = toolCall;
48257
- this.friskToolId = friskToolId ?? null;
48258
- this.friskToolVersionId = friskToolVersionId ?? null;
48259
- this.agentState = agentState;
48260
- this.parent = parent;
48261
- this.tracer = tracer;
48262
- this.redaction = resolveRedactionOptions(redact);
48210
+ this._spanName = spanName;
48211
+ this._attributeFields = attributeFields;
48212
+ const parentContext = parent ? import_api.trace.setSpan(import_api.context.active(), parent.otelSpan) : import_api.context.active();
48213
+ this._otelSpan = tracer.startSpan(this._spanName, undefined, parentContext);
48263
48214
  }
48264
- get span() {
48265
- if (!this._span) {
48266
- throw new ToolCallSpanNotInitializedError;
48267
- }
48268
- return this._span;
48215
+ get otelSpan() {
48216
+ return this._otelSpan;
48269
48217
  }
48270
- get traceContextCarrier() {
48271
- return this._traceContextCarrier;
48218
+ get spanId() {
48219
+ return this._otelSpan.spanContext().spanId;
48272
48220
  }
48273
- run(callback) {
48274
- this.enter();
48275
- try {
48276
- return callback(this);
48277
- } finally {
48278
- this.exit();
48221
+ setAttribute(field, value) {
48222
+ this.setAttributesByField({ [field]: value });
48223
+ }
48224
+ getAttribute(field) {
48225
+ return this._attributes[this.constantFor(field)];
48226
+ }
48227
+ end() {
48228
+ if (this._ended) {
48229
+ return;
48279
48230
  }
48231
+ this._ended = true;
48232
+ this._otelSpan.end();
48280
48233
  }
48281
- async runAsync(callback) {
48282
- this.enter();
48283
- try {
48284
- return await callback(this);
48285
- } finally {
48286
- this.exit();
48234
+ setAttributesByField(values) {
48235
+ for (const [field, value] of Object.entries(values)) {
48236
+ const constant = this.constantFor(field);
48237
+ if (value === null || value === undefined) {
48238
+ continue;
48239
+ }
48240
+ this._attributes[constant] = value;
48241
+ this._otelSpan.setAttribute(constant, value);
48287
48242
  }
48288
48243
  }
48289
- setAttribute(key, value) {
48290
- this.span.setAttribute(key, value);
48244
+ constantFor(field) {
48245
+ const constant = this._attributeFields[field];
48246
+ if (constant === undefined) {
48247
+ throw new Error(`Unknown attribute '${field}' for ${this.constructor.name}`);
48248
+ }
48249
+ return constant;
48250
+ }
48251
+ }
48252
+ // src/telemetry/constants.ts
48253
+ var TRACER_NAME = "frisk_js_sdk";
48254
+ var TRACER_VERSION = "0.1.0";
48255
+ var SPAN_NAME_DECIDE_TOOL_CALL = "frisk.tool_call.decide";
48256
+ var SPAN_NAME_OBSERVE_TOOL_CALL = "frisk.tool_call.observation";
48257
+ var SPAN_NAME_LLM_CALL = "frisk.llm_call";
48258
+ var SPAN_NAME_OPERATION = "frisk.operation";
48259
+ var SPAN_NAME_FRISK_SESSION = "frisk.session";
48260
+ var ATTRIBUTE_NAME_LLM_CALL_SPAN_ID = "frisk.tool_call.llm_call_span_id";
48261
+ var ATTRIBUTE_NAME_LLM_CALL_PROMPTS_JSON = "frisk.llm_call.prompts.json";
48262
+ var ATTRIBUTE_NAME_LLM_CALL_RESPONSES_JSON = "frisk.llm_call.responses.json";
48263
+ var ATTRIBUTE_NAME_LLM_CALL_TOOL_CALLS_JSON = "frisk.llm_call.tool_calls.json";
48264
+ var ATTRIBUTE_NAME_MODEL_NAME = "frisk.model.name";
48265
+ var ATTRIBUTE_NAME_MODEL_PROVIDER = "frisk.model.provider";
48266
+ var ATTRIBUTE_NAME_TOKEN_USAGE_INPUT_TOKENS = "frisk.token_usage.input_tokens";
48267
+ var ATTRIBUTE_NAME_TOKEN_USAGE_OUTPUT_TOKENS = "frisk.token_usage.output_tokens";
48268
+ var ATTRIBUTE_NAME_TOKEN_USAGE_TOTAL_TOKENS = "frisk.token_usage.total_tokens";
48269
+ var ATTRIBUTE_NAME_SESSION_PROMPT = "frisk.session.prompt";
48270
+ var ATTRIBUTE_NAME_SESSION_ID = "frisk.session.id";
48271
+ var ATTRIBUTE_NAME_REMOTE_SESSION_ID = "frisk.session.remote_id";
48272
+ var ATTRIBUTE_NAME_LLM_REASONING = "frisk.llm_reasoning";
48273
+ var ATTRIBUTE_NAME_TOOL_NAME = "frisk.tool.name";
48274
+ var ATTRIBUTE_NAME_FRISK_TOOL_ID = "frisk.tool.id";
48275
+ var ATTRIBUTE_NAME_FRISK_TOOL_VERSION_ID = "frisk.tool.version_id";
48276
+ var ATTRIBUTE_NAME_TOOL_CALL_ID = "frisk.tool_call.id";
48277
+ var ATTRIBUTE_NAME_TOOL_ARGS_JSON = "frisk.tool.args.json";
48278
+ var ATTRIBUTE_NAME_TOOL_ARGS_REDACTED_PATHS_JSON = "frisk.tool.args_redacted_paths.json";
48279
+ var ATTRIBUTE_NAME_AGENT_STATE_JSON = "frisk.agent_state.json";
48280
+ var ATTRIBUTE_NAME_AGENT_STATE_REDACTED_PATHS_JSON = "frisk.agent_state_redacted_paths.json";
48281
+ var ATTRIBUTE_NAME_DECISION_MATCHED_RULE_COUNT = "frisk.decision.matched_rule_count";
48282
+ var ATTRIBUTE_NAME_DECISION_OUTCOME = "frisk.decision.outcome";
48283
+ var ATTRIBUTE_NAME_DECISION_REASON = "frisk.decision.reason";
48284
+ var ATTRIBUTE_NAME_ERROR_TYPE = "error.type";
48285
+ var ATTRIBUTE_NAME_ERROR_MESSAGE = "error.message";
48286
+ var ATTRIBUTE_NAME_TOOL_CALL_IS_SUCCESS = "frisk.tool_call.is_success";
48287
+ var ATTRIBUTE_NAME_TOOL_CALL_IS_ERROR = "frisk.tool_call.is_error";
48288
+ var ATTRIBUTE_NAME_TOOL_CALL_COUNT = "frisk.tool_calls.count";
48289
+ var ATTRIBUTE_NAME_TOOL_CALL_ERROR_COUNT = "frisk.tool_calls.error_count";
48290
+ var ATTRIBUTE_NAME_TOOL_CALL_SEQUENCE_NUMBER = "frisk.tool_call.sequence_number";
48291
+
48292
+ // src/core/spans/llm-call-span.ts
48293
+ var FIELDS = {
48294
+ sessionId: ATTRIBUTE_NAME_SESSION_ID,
48295
+ promptsJson: ATTRIBUTE_NAME_LLM_CALL_PROMPTS_JSON,
48296
+ responsesJson: ATTRIBUTE_NAME_LLM_CALL_RESPONSES_JSON,
48297
+ toolCallsJson: ATTRIBUTE_NAME_LLM_CALL_TOOL_CALLS_JSON,
48298
+ modelName: ATTRIBUTE_NAME_MODEL_NAME,
48299
+ modelProvider: ATTRIBUTE_NAME_MODEL_PROVIDER,
48300
+ inputTokens: ATTRIBUTE_NAME_TOKEN_USAGE_INPUT_TOKENS,
48301
+ outputTokens: ATTRIBUTE_NAME_TOKEN_USAGE_OUTPUT_TOKENS,
48302
+ totalTokens: ATTRIBUTE_NAME_TOKEN_USAGE_TOTAL_TOKENS,
48303
+ errorType: ATTRIBUTE_NAME_ERROR_TYPE,
48304
+ errorMessage: ATTRIBUTE_NAME_ERROR_MESSAGE
48305
+ };
48306
+
48307
+ class LlmCallSpan extends FriskSpan {
48308
+ constructor(args) {
48309
+ super({ ...args, spanName: SPAN_NAME_LLM_CALL, attributeFields: FIELDS });
48310
+ }
48311
+ setAttributes(values) {
48312
+ this.setAttributesByField(values);
48291
48313
  }
48292
- setAttributes(attributes) {
48293
- this.span.setAttributes(attributes);
48314
+ }
48315
+ // src/core/spans/operation-span.ts
48316
+ var FIELDS2 = {
48317
+ sessionId: ATTRIBUTE_NAME_SESSION_ID
48318
+ };
48319
+
48320
+ class OperationSpan extends FriskSpan {
48321
+ constructor(args) {
48322
+ super({ ...args, spanName: SPAN_NAME_OPERATION, attributeFields: FIELDS2 });
48294
48323
  }
48295
- saveResult(decision) {
48296
- if (!this.span) {
48297
- return;
48298
- }
48299
- this.setAttributes({
48300
- [ATTRIBUTE_NAME_DECISION_OUTCOME]: decision.outcome,
48301
- [ATTRIBUTE_NAME_DECISION_MATCHED_RULE_COUNT]: Number(decision.rulesMatchedCount)
48324
+ setAttributes(values) {
48325
+ this.setAttributesByField(values);
48326
+ }
48327
+ }
48328
+ // src/core/spans/session-span.ts
48329
+ var FIELDS3 = {
48330
+ sessionId: ATTRIBUTE_NAME_SESSION_ID,
48331
+ remoteSessionId: ATTRIBUTE_NAME_REMOTE_SESSION_ID,
48332
+ prompt: ATTRIBUTE_NAME_SESSION_PROMPT,
48333
+ toolCallCount: ATTRIBUTE_NAME_TOOL_CALL_COUNT,
48334
+ toolCallErrorCount: ATTRIBUTE_NAME_TOOL_CALL_ERROR_COUNT,
48335
+ inputTokens: ATTRIBUTE_NAME_TOKEN_USAGE_INPUT_TOKENS,
48336
+ outputTokens: ATTRIBUTE_NAME_TOKEN_USAGE_OUTPUT_TOKENS,
48337
+ totalTokens: ATTRIBUTE_NAME_TOKEN_USAGE_TOTAL_TOKENS
48338
+ };
48339
+
48340
+ class SessionSpan extends FriskSpan {
48341
+ constructor(args) {
48342
+ super({
48343
+ ...args,
48344
+ spanName: SPAN_NAME_FRISK_SESSION,
48345
+ attributeFields: FIELDS3
48302
48346
  });
48303
- if (decision.reason) {
48304
- this.setAttribute(ATTRIBUTE_NAME_DECISION_REASON, decision.reason);
48305
- }
48306
48347
  }
48307
- saveError(error2) {
48308
- if (!this.span) {
48309
- return;
48310
- }
48311
- const errorMessage = error2 instanceof Error ? error2.message : String(error2);
48312
- const errorType = error2 instanceof Error ? error2.constructor.name : typeof error2;
48313
- this.setAttributes({
48314
- [ATTRIBUTE_NAME_ERROR_TYPE]: errorType,
48315
- [ATTRIBUTE_NAME_ERROR_MESSAGE]: errorMessage
48348
+ setAttributes(values) {
48349
+ this.setAttributesByField(values);
48350
+ }
48351
+ }
48352
+ // src/core/spans/tool-call-decision-span.ts
48353
+ var FIELDS4 = {
48354
+ sessionId: ATTRIBUTE_NAME_SESSION_ID,
48355
+ toolName: ATTRIBUTE_NAME_TOOL_NAME,
48356
+ toolCallId: ATTRIBUTE_NAME_TOOL_CALL_ID,
48357
+ toolArgsJson: ATTRIBUTE_NAME_TOOL_ARGS_JSON,
48358
+ toolArgsRedactedPathsJson: ATTRIBUTE_NAME_TOOL_ARGS_REDACTED_PATHS_JSON,
48359
+ agentStateJson: ATTRIBUTE_NAME_AGENT_STATE_JSON,
48360
+ agentStateRedactedPathsJson: ATTRIBUTE_NAME_AGENT_STATE_REDACTED_PATHS_JSON,
48361
+ friskToolId: ATTRIBUTE_NAME_FRISK_TOOL_ID,
48362
+ friskToolVersionId: ATTRIBUTE_NAME_FRISK_TOOL_VERSION_ID,
48363
+ llmReasoning: ATTRIBUTE_NAME_LLM_REASONING,
48364
+ decisionOutcome: ATTRIBUTE_NAME_DECISION_OUTCOME,
48365
+ decisionMatchedRuleCount: ATTRIBUTE_NAME_DECISION_MATCHED_RULE_COUNT,
48366
+ decisionReason: ATTRIBUTE_NAME_DECISION_REASON,
48367
+ errorType: ATTRIBUTE_NAME_ERROR_TYPE,
48368
+ errorMessage: ATTRIBUTE_NAME_ERROR_MESSAGE
48369
+ };
48370
+
48371
+ class ToolCallDecisionSpan extends FriskSpan {
48372
+ constructor(args) {
48373
+ super({
48374
+ ...args,
48375
+ spanName: SPAN_NAME_DECIDE_TOOL_CALL,
48376
+ attributeFields: FIELDS4
48316
48377
  });
48317
48378
  }
48318
- enter() {
48319
- const parentContext = this.parent ? import_api.trace.setSpan(import_api.context.active(), this.parent) : import_api.context.active();
48320
- const redactedToolArgsResult = this.adapter.serializeToolArgs(removeLlmReasoningArg(this.toolCall.args), { redact: this.redaction.redactToolArgs });
48321
- const redactedAgentStateResult = this.adapter.serializeAgentState(this.agentState, { redact: this.redaction.redactAgentState });
48322
- this._span = this.tracer.startSpan(SPAN_NAME_DECIDE_TOOL_CALL, {
48323
- attributes: {
48324
- [ATTRIBUTE_NAME_SESSION_ID]: this.sessionId,
48325
- [ATTRIBUTE_NAME_TOOL_NAME]: this.toolCall.name,
48326
- ...this.friskToolId !== null ? { [ATTRIBUTE_NAME_FRISK_TOOL_ID]: this.friskToolId } : {},
48327
- ...this.friskToolVersionId !== null ? {
48328
- [ATTRIBUTE_NAME_FRISK_TOOL_VERSION_ID]: this.friskToolVersionId
48329
- } : {},
48330
- [ATTRIBUTE_NAME_TOOL_CALL_ID]: this.toolCall.id,
48331
- [ATTRIBUTE_NAME_TOOL_ARGS_JSON]: redactedToolArgsResult.value ?? "",
48332
- [ATTRIBUTE_NAME_TOOL_ARGS_REDACTED_PATHS_JSON]: JSON.stringify(redactedToolArgsResult.redactedPaths),
48333
- [ATTRIBUTE_NAME_AGENT_STATE_JSON]: redactedAgentStateResult.value ?? "",
48334
- [ATTRIBUTE_NAME_AGENT_STATE_REDACTED_PATHS_JSON]: JSON.stringify(redactedAgentStateResult.redactedPaths)
48335
- }
48336
- }, parentContext);
48337
- this._traceContextCarrier = {};
48338
- const spanContext = import_api.trace.setSpan(import_api.context.active(), this.span);
48339
- import_api.propagation.inject(spanContext, this._traceContextCarrier);
48340
- }
48341
- exit() {
48342
- if (!this.span) {
48343
- return;
48344
- }
48345
- this.span.end();
48379
+ setAttributes(values) {
48380
+ this.setAttributesByField(values);
48346
48381
  }
48347
48382
  }
48383
+ // src/core/spans/tool-call-observation-span.ts
48384
+ var FIELDS5 = {
48385
+ sessionId: ATTRIBUTE_NAME_SESSION_ID,
48386
+ toolName: ATTRIBUTE_NAME_TOOL_NAME,
48387
+ toolCallId: ATTRIBUTE_NAME_TOOL_CALL_ID,
48388
+ toolArgsJson: ATTRIBUTE_NAME_TOOL_ARGS_JSON,
48389
+ toolArgsRedactedPathsJson: ATTRIBUTE_NAME_TOOL_ARGS_REDACTED_PATHS_JSON,
48390
+ agentStateJson: ATTRIBUTE_NAME_AGENT_STATE_JSON,
48391
+ agentStateRedactedPathsJson: ATTRIBUTE_NAME_AGENT_STATE_REDACTED_PATHS_JSON,
48392
+ toolCallSequenceNumber: ATTRIBUTE_NAME_TOOL_CALL_SEQUENCE_NUMBER,
48393
+ friskToolId: ATTRIBUTE_NAME_FRISK_TOOL_ID,
48394
+ friskToolVersionId: ATTRIBUTE_NAME_FRISK_TOOL_VERSION_ID,
48395
+ llmReasoning: ATTRIBUTE_NAME_LLM_REASONING,
48396
+ isSuccess: ATTRIBUTE_NAME_TOOL_CALL_IS_SUCCESS,
48397
+ isError: ATTRIBUTE_NAME_TOOL_CALL_IS_ERROR,
48398
+ errorMessage: ATTRIBUTE_NAME_ERROR_MESSAGE,
48399
+ errorType: ATTRIBUTE_NAME_ERROR_TYPE,
48400
+ llmCallSpanId: ATTRIBUTE_NAME_LLM_CALL_SPAN_ID
48401
+ };
48348
48402
 
48403
+ class ToolCallObservationSpan extends FriskSpan {
48404
+ constructor(args) {
48405
+ super({
48406
+ ...args,
48407
+ spanName: SPAN_NAME_OBSERVE_TOOL_CALL,
48408
+ attributeFields: FIELDS5
48409
+ });
48410
+ }
48411
+ setAttributes(values) {
48412
+ this.setAttributesByField(values);
48413
+ }
48414
+ }
48349
48415
  // src/core/types.ts
48350
48416
  var DecisionOutcome;
48351
48417
  ((DecisionOutcome2) => {
@@ -48369,6 +48435,9 @@ class FriskSession {
48369
48435
  toolCallSequenceNumber = 0;
48370
48436
  toolCallSequenceGenerator = this.createToolCallSequenceGenerator();
48371
48437
  toolCallErrorCount = 0;
48438
+ tokenUsageInput = 0;
48439
+ tokenUsageOutput = 0;
48440
+ tokenUsageTotal = 0;
48372
48441
  constructor({ frisk, redact, tracer, logging }) {
48373
48442
  const sessionId = this.constructor.generateSessionId();
48374
48443
  this.logger = deriveSdkLogger(logging, {
@@ -48391,12 +48460,34 @@ class FriskSession {
48391
48460
  get rootRunId() {
48392
48461
  return this._rootRunId;
48393
48462
  }
48463
+ createLlmCallSpan({
48464
+ parent
48465
+ } = {}) {
48466
+ const span = new LlmCallSpan({
48467
+ tracer: this.tracer,
48468
+ parent: parent ?? this._rootSpan
48469
+ });
48470
+ span.setAttributes({ sessionId: this.id });
48471
+ return span;
48472
+ }
48473
+ createOperationSpan({
48474
+ parent
48475
+ } = {}) {
48476
+ const span = new OperationSpan({
48477
+ tracer: this.tracer,
48478
+ parent: parent ?? this._rootSpan
48479
+ });
48480
+ span.setAttributes({ sessionId: this.id });
48481
+ return span;
48482
+ }
48394
48483
  async createToolCallSpan({
48395
48484
  name,
48396
48485
  args: toolArgsInput,
48397
- agentState
48486
+ agentState,
48487
+ parent
48398
48488
  }) {
48399
48489
  const toolArgs = this.validateToolArgs(toolArgsInput);
48490
+ const llmReasoning = extractLlmReasoning(toolArgs);
48400
48491
  const redactedToolArgsResult = this.frisk.adapter?.serializeToolArgs(removeLlmReasoningArg(toolArgs), { redact: this.redaction.redactToolArgs }) ?? {
48401
48492
  value: "{}",
48402
48493
  redactedPaths: []
@@ -48406,26 +48497,30 @@ class FriskSession {
48406
48497
  value: "{}",
48407
48498
  redactedPaths: []
48408
48499
  };
48409
- const sessionSpan = this.rootSpan;
48410
- const parentContext = sessionSpan ? import_api2.trace.setSpan(import_api2.context.active(), sessionSpan) : import_api2.context.active();
48411
- const spanAttributes = {
48412
- [ATTRIBUTE_NAME_SESSION_ID]: this.id,
48413
- [ATTRIBUTE_NAME_TOOL_NAME]: name,
48414
- [ATTRIBUTE_NAME_TOOL_ARGS_JSON]: redactedToolArgsResult.value,
48415
- [ATTRIBUTE_NAME_TOOL_ARGS_REDACTED_PATHS_JSON]: JSON.stringify(redactedToolArgsResult.redactedPaths),
48416
- [ATTRIBUTE_NAME_AGENT_STATE_JSON]: redactedAgentStateResult.value ?? "{}",
48417
- [ATTRIBUTE_NAME_AGENT_STATE_REDACTED_PATHS_JSON]: JSON.stringify(redactedAgentStateResult.redactedPaths),
48418
- [ATTRIBUTE_NAME_TOOL_CALL_SEQUENCE_NUMBER]: this.toolCallSequenceGenerator.next().value
48419
- };
48500
+ const span = new ToolCallObservationSpan({
48501
+ tracer: this.tracer,
48502
+ parent: parent ?? this._rootSpan
48503
+ });
48504
+ span.setAttributes({
48505
+ sessionId: this.id,
48506
+ toolName: name,
48507
+ toolArgsJson: redactedToolArgsResult.value ?? "{}",
48508
+ toolArgsRedactedPathsJson: JSON.stringify(redactedToolArgsResult.redactedPaths),
48509
+ agentStateJson: redactedAgentStateResult.value ?? "{}",
48510
+ agentStateRedactedPathsJson: JSON.stringify(redactedAgentStateResult.redactedPaths),
48511
+ toolCallSequenceNumber: this.toolCallSequenceGenerator.next().value
48512
+ });
48420
48513
  await this.frisk.toolRegistrationComplete;
48421
48514
  const registeredTool = this.frisk.getRegisteredTool(name);
48422
48515
  if (registeredTool) {
48423
- spanAttributes[ATTRIBUTE_NAME_FRISK_TOOL_ID] = registeredTool.id;
48424
- spanAttributes[ATTRIBUTE_NAME_FRISK_TOOL_VERSION_ID] = registeredTool.versionId;
48516
+ span.setAttributes({
48517
+ friskToolId: registeredTool.id,
48518
+ friskToolVersionId: registeredTool.versionId
48519
+ });
48520
+ }
48521
+ if (llmReasoning !== null) {
48522
+ span.setAttributes({ llmReasoning });
48425
48523
  }
48426
- const span = this.getTracer().startSpan(SPAN_NAME_OBSERVE_TOOL_CALL, {
48427
- attributes: spanAttributes
48428
- }, parentContext);
48429
48524
  return span;
48430
48525
  }
48431
48526
  closeToolCallSpan({
@@ -48435,19 +48530,19 @@ class FriskSession {
48435
48530
  status
48436
48531
  }) {
48437
48532
  if (toolCallId) {
48438
- span.setAttribute(ATTRIBUTE_NAME_TOOL_CALL_ID, toolCallId);
48533
+ span.setAttributes({ toolCallId });
48439
48534
  }
48440
48535
  if (status === "error" /* Error */ || !!err) {
48441
48536
  this.incrementToolCallErrors();
48442
- span.setAttribute(ATTRIBUTE_NAME_TOOL_CALL_IS_ERROR, true);
48443
- span.setAttribute(ATTRIBUTE_NAME_TOOL_CALL_IS_SUCCESS, false);
48537
+ span.setAttributes({ isError: true, isSuccess: false });
48444
48538
  } else if (status === "success" /* Success */) {
48445
- span.setAttribute(ATTRIBUTE_NAME_TOOL_CALL_IS_SUCCESS, true);
48446
- span.setAttribute(ATTRIBUTE_NAME_TOOL_CALL_IS_ERROR, false);
48539
+ span.setAttributes({ isSuccess: true, isError: false });
48447
48540
  }
48448
- if (err && err instanceof Error) {
48449
- span.setAttribute(ATTRIBUTE_NAME_ERROR_MESSAGE, `${err}`);
48450
- span.setAttribute(ATTRIBUTE_NAME_ERROR_TYPE, `${err.constructor.name}`);
48541
+ if (err instanceof Error) {
48542
+ span.setAttributes({
48543
+ errorMessage: `${err}`,
48544
+ errorType: `${err.constructor.name}`
48545
+ });
48451
48546
  }
48452
48547
  span.end();
48453
48548
  }
@@ -48461,32 +48556,37 @@ class FriskSession {
48461
48556
  agentState
48462
48557
  }) {
48463
48558
  const registeredTool = this.frisk.getRegisteredTool(toolCall.name);
48464
- const toolCallSpan = new ToolCallSpan({
48465
- sessionId: this.id,
48466
- adapter: this.frisk.adapter,
48467
- toolCall,
48468
- friskToolId: registeredTool?.id ?? null,
48469
- friskToolVersionId: registeredTool?.versionId ?? null,
48470
- agentState,
48471
- parent: this._rootSpan,
48559
+ const redactedToolArgs = this.frisk.adapter.serializeToolArgs(removeLlmReasoningArg(toolCall.args), { redact: this.redaction.redactToolArgs });
48560
+ const redactedAgentState = this.frisk.adapter.serializeAgentState(agentState, { redact: this.redaction.redactAgentState });
48561
+ const llmReasoning = extractLlmReasoning(toolCall.args);
48562
+ const span = new ToolCallDecisionSpan({
48472
48563
  tracer: this.tracer,
48473
- redact: this.redaction
48564
+ parent: this._rootSpan
48474
48565
  });
48475
- const toolArgs = toolCall.args;
48476
- return toolCallSpan.run((span) => {
48566
+ try {
48567
+ span.setAttributes({
48568
+ sessionId: this.id,
48569
+ toolName: toolCall.name,
48570
+ toolCallId: toolCall.id,
48571
+ toolArgsJson: redactedToolArgs.value ?? "{}",
48572
+ toolArgsRedactedPathsJson: JSON.stringify(redactedToolArgs.redactedPaths),
48573
+ agentStateJson: redactedAgentState.value ?? "{}",
48574
+ agentStateRedactedPathsJson: JSON.stringify(redactedAgentState.redactedPaths),
48575
+ friskToolId: registeredTool?.id,
48576
+ friskToolVersionId: registeredTool?.versionId,
48577
+ llmReasoning: llmReasoning ?? undefined
48578
+ });
48579
+ const spanContext = import_api2.trace.setSpan(import_api2.context.active(), span.otelSpan);
48580
+ const traceContextCarrier = {};
48581
+ import_api2.propagation.inject(spanContext, traceContextCarrier);
48477
48582
  try {
48478
- if (LLM_REASONING_ARG_NAME in toolArgs) {
48479
- const llmReasoning = toolArgs[LLM_REASONING_ARG_NAME];
48480
- span.setAttribute(ATTRIBUTE_NAME_LLM_REASONING, llmReasoning);
48481
- }
48482
- const baseToolCallArgs = removeLlmReasoningArg(toolCall.args);
48483
48583
  const coreResult = this.frisk.decideToolCall({
48484
48584
  toolCall: {
48485
48585
  ...toolCall,
48486
- args: baseToolCallArgs
48586
+ args: removeLlmReasoningArg(toolCall.args)
48487
48587
  },
48488
48588
  agentState,
48489
- traceContextCarrier: span.traceContextCarrier ?? undefined
48589
+ traceContextCarrier
48490
48590
  });
48491
48591
  const result = {
48492
48592
  outcome: coreResult.outcome,
@@ -48495,7 +48595,11 @@ class FriskSession {
48495
48595
  policyId: coreResult.policyId,
48496
48596
  policyVersionId: coreResult.policyVersionId
48497
48597
  };
48498
- span.saveResult(result);
48598
+ span.setAttributes({
48599
+ decisionOutcome: result.outcome,
48600
+ decisionMatchedRuleCount: Number(result.rulesMatchedCount),
48601
+ decisionReason: result.reason ?? undefined
48602
+ });
48499
48603
  return result;
48500
48604
  } catch (error2) {
48501
48605
  const wrapped = new ToolCallEvaluationError(error2);
@@ -48503,14 +48607,19 @@ class FriskSession {
48503
48607
  toolName: toolCall.name,
48504
48608
  toolCallId: toolCall.id
48505
48609
  });
48506
- span.saveError(wrapped);
48610
+ span.setAttributes({
48611
+ errorType: wrapped.constructor.name,
48612
+ errorMessage: wrapped.message
48613
+ });
48507
48614
  return {
48508
48615
  outcome: "error" /* ERROR */,
48509
48616
  rulesMatchedCount: 0,
48510
48617
  reason: wrapped.message
48511
48618
  };
48512
48619
  }
48513
- });
48620
+ } finally {
48621
+ span.end();
48622
+ }
48514
48623
  }
48515
48624
  *createToolCallSequenceGenerator() {
48516
48625
  while (true) {
@@ -48526,24 +48635,49 @@ class FriskSession {
48526
48635
  getToolCallErrorCount() {
48527
48636
  return this.toolCallErrorCount;
48528
48637
  }
48638
+ recordTokenUsage({
48639
+ inputTokens = 0,
48640
+ outputTokens = 0,
48641
+ totalTokens = 0
48642
+ }) {
48643
+ this.tokenUsageInput += inputTokens;
48644
+ this.tokenUsageOutput += outputTokens;
48645
+ this.tokenUsageTotal += totalTokens;
48646
+ this._rootSpan?.setAttributes({
48647
+ inputTokens: this.tokenUsageInput,
48648
+ outputTokens: this.tokenUsageOutput,
48649
+ totalTokens: this.tokenUsageTotal
48650
+ });
48651
+ }
48652
+ getTokenUsage() {
48653
+ return {
48654
+ inputTokens: this.tokenUsageInput,
48655
+ outputTokens: this.tokenUsageOutput,
48656
+ totalTokens: this.tokenUsageTotal
48657
+ };
48658
+ }
48529
48659
  initTracing({ runId, agentState }) {
48530
48660
  this._rootRunId = runId;
48531
48661
  this._isTracing = true;
48532
48662
  this._agentState = agentState;
48533
- const span = this.tracer.startSpan(SPAN_NAME_FRISK_SESSION);
48534
- span.setAttribute(ATTRIBUTE_NAME_SESSION_ID, this.id);
48535
- span.setAttribute(ATTRIBUTE_NAME_REMOTE_SESSION_ID, runId);
48663
+ const span = new SessionSpan({ tracer: this.tracer });
48664
+ span.setAttributes({ sessionId: this.id, remoteSessionId: runId });
48536
48665
  const userPrompt = this.frisk.adapter.extractPrompt?.(agentState);
48537
48666
  if (userPrompt) {
48538
- span.setAttribute(ATTRIBUTE_NAME_SESSION_PROMPT, userPrompt);
48667
+ span.setAttributes({ prompt: userPrompt });
48539
48668
  }
48540
48669
  this.setRootSpan(span);
48541
48670
  return span;
48542
48671
  }
48543
48672
  endTracing() {
48544
48673
  if (this._rootSpan) {
48545
- this._rootSpan.setAttribute(ATTRIBUTE_NAME_TOOL_CALL_COUNT, this.getToolCallCount());
48546
- this._rootSpan.setAttribute(ATTRIBUTE_NAME_TOOL_CALL_ERROR_COUNT, this.getToolCallErrorCount());
48674
+ this._rootSpan.setAttributes({
48675
+ toolCallCount: this.getToolCallCount(),
48676
+ toolCallErrorCount: this.getToolCallErrorCount(),
48677
+ inputTokens: this.tokenUsageInput,
48678
+ outputTokens: this.tokenUsageOutput,
48679
+ totalTokens: this.tokenUsageTotal
48680
+ });
48547
48681
  this._rootSpan.end();
48548
48682
  }
48549
48683
  this._isTracing = false;
@@ -48563,6 +48697,7 @@ class FriskCallbackHandler extends BaseCallbackHandler {
48563
48697
  name = "FriskCallbackHandler";
48564
48698
  session;
48565
48699
  spansByRunId;
48700
+ llmCallSpanIdByToolCallId;
48566
48701
  frisk;
48567
48702
  logger;
48568
48703
  constructor({
@@ -48574,23 +48709,58 @@ class FriskCallbackHandler extends BaseCallbackHandler {
48574
48709
  this.session = session;
48575
48710
  this.frisk = frisk;
48576
48711
  this.spansByRunId = new Map;
48712
+ this.llmCallSpanIdByToolCallId = new Map;
48577
48713
  this.logger = deriveSdkLogger(logging, {
48578
48714
  component: "FriskCallbackHandler"
48579
48715
  });
48580
48716
  }
48581
48717
  handleChainStart(_chain, inputs, runId, parentRunId) {
48718
+ let span;
48582
48719
  if (parentRunId === undefined) {
48583
- this.session.initTracing({
48720
+ span = this.session.initTracing({
48584
48721
  runId,
48585
48722
  agentState: inputs
48586
48723
  });
48724
+ } else {
48725
+ span = this.session.createOperationSpan({
48726
+ parent: this.resolveParentSpan(parentRunId)
48727
+ });
48587
48728
  }
48729
+ this.spansByRunId.set(runId, span);
48588
48730
  }
48589
48731
  handleChainEnd(_outputs, runId, _parentRunId, _tags, _kwargs) {
48590
48732
  if (this.session.rootRunId === runId) {
48733
+ this.spansByRunId.delete(runId);
48734
+ for (const span of this.spansByRunId.values()) {
48735
+ span.end();
48736
+ }
48737
+ this.spansByRunId.clear();
48738
+ this.llmCallSpanIdByToolCallId.clear();
48591
48739
  this.session.endTracing();
48740
+ return;
48741
+ }
48742
+ this.endSpan(runId);
48743
+ }
48744
+ handleChatModelStart(_llm, messages, runId, parentRunId) {
48745
+ const span = this.openLlmCallSpan(runId, parentRunId);
48746
+ const promptsJson = this.safeJsonStringify(this.getPromptMessages(messages), "chat prompt messages");
48747
+ if (promptsJson !== null) {
48748
+ span.setAttributes({ promptsJson });
48749
+ }
48750
+ }
48751
+ handleLLMStart(_llm, prompts, runId, parentRunId) {
48752
+ const span = this.openLlmCallSpan(runId, parentRunId);
48753
+ const promptsJson = this.safeJsonStringify(prompts, "LLM prompts");
48754
+ if (promptsJson !== null) {
48755
+ span.setAttributes({ promptsJson });
48592
48756
  }
48593
48757
  }
48758
+ handleLLMEnd(output, runId) {
48759
+ this.finalizeLlmCall(output, runId, null);
48760
+ }
48761
+ handleLLMError(err, runId) {
48762
+ this.finalizeLlmCall(null, runId, err);
48763
+ }
48594
48764
  async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
48595
48765
  const toolName = runName;
48596
48766
  if (!toolName) {
@@ -48608,18 +48778,20 @@ class FriskCallbackHandler extends BaseCallbackHandler {
48608
48778
  }
48609
48779
  const span = await this.session.createToolCallSpan({
48610
48780
  name: toolName,
48611
- args: parsedToolArgs
48781
+ args: parsedToolArgs,
48782
+ parent: this.resolveParentSpan(parentRunId)
48612
48783
  });
48613
48784
  this.spansByRunId.set(runId, span);
48614
48785
  }
48615
48786
  async handleToolEnd(output, runId, parentRunId, tags) {
48616
48787
  const span = this.spansByRunId.get(runId);
48617
- if (!span) {
48788
+ if (!(span instanceof ToolCallObservationSpan)) {
48618
48789
  captureError(new Error("Langchain invoked handleToolEnd but no span was found for the given runId. This tool call won't be included in Frisk telemetry data."), this.logger);
48619
48790
  return;
48620
48791
  }
48621
48792
  const toolCallId = output.tool_call_id;
48622
48793
  const status = output.status;
48794
+ this.stampLlmCallSpanId(span, toolCallId);
48623
48795
  this.closeToolCallSpan({
48624
48796
  toolCallId,
48625
48797
  span,
@@ -48630,7 +48802,7 @@ class FriskCallbackHandler extends BaseCallbackHandler {
48630
48802
  }
48631
48803
  async handleToolError(err, runId, parentRunId, tags) {
48632
48804
  const span = this.spansByRunId.get(runId);
48633
- if (!span) {
48805
+ if (!(span instanceof ToolCallObservationSpan)) {
48634
48806
  captureError(new Error("Langchain invoked handleToolError but no span was found for the given runId. This tool call won't be included in Frisk telemetry data."), this.logger);
48635
48807
  return;
48636
48808
  }
@@ -48642,6 +48814,144 @@ class FriskCallbackHandler extends BaseCallbackHandler {
48642
48814
  });
48643
48815
  this.spansByRunId.delete(runId);
48644
48816
  }
48817
+ resolveParentSpan(parentRunId) {
48818
+ if (parentRunId === undefined) {
48819
+ return null;
48820
+ }
48821
+ return this.spansByRunId.get(parentRunId) ?? null;
48822
+ }
48823
+ openLlmCallSpan(runId, parentRunId) {
48824
+ const existing = this.spansByRunId.get(runId);
48825
+ if (existing instanceof LlmCallSpan) {
48826
+ return existing;
48827
+ }
48828
+ const span = this.session.createLlmCallSpan({
48829
+ parent: this.resolveParentSpan(parentRunId)
48830
+ });
48831
+ this.spansByRunId.set(runId, span);
48832
+ return span;
48833
+ }
48834
+ safeJsonStringify(value, what) {
48835
+ try {
48836
+ return JSON.stringify(value);
48837
+ } catch (e) {
48838
+ captureError(new Error(`Failed to serialize ${what} for Frisk telemetry`, {
48839
+ cause: e
48840
+ }), this.logger);
48841
+ return null;
48842
+ }
48843
+ }
48844
+ getPromptMessages(messages) {
48845
+ const lastBatch = messages[messages.length - 1];
48846
+ if (!lastBatch || lastBatch.length === 0) {
48847
+ return [];
48848
+ }
48849
+ const collected = [];
48850
+ for (let i = lastBatch.length - 1;i >= 0; i--) {
48851
+ const message = lastBatch[i];
48852
+ const type = message.getType();
48853
+ if (type === "ai") {
48854
+ break;
48855
+ }
48856
+ const entry = { type, content: message.content };
48857
+ if (type === "tool") {
48858
+ const toolMessage = message;
48859
+ entry.metadata = {
48860
+ tool_name: toolMessage.name ?? null,
48861
+ tool_call_id: toolMessage.tool_call_id ?? null
48862
+ };
48863
+ }
48864
+ collected.push(entry);
48865
+ }
48866
+ collected.reverse();
48867
+ return collected;
48868
+ }
48869
+ finalizeLlmCall(output, runId, err) {
48870
+ const found = this.spansByRunId.get(runId) ?? null;
48871
+ const llmCallSpan = found instanceof LlmCallSpan ? found : null;
48872
+ const generations = output?.generations ?? [];
48873
+ const responses = [];
48874
+ const toolCalls = [];
48875
+ let modelName;
48876
+ let modelProvider;
48877
+ let inputTokens = 0;
48878
+ let outputTokens = 0;
48879
+ let totalTokens = 0;
48880
+ let hasUsage = false;
48881
+ for (const generationList of generations) {
48882
+ for (const generation of generationList) {
48883
+ const message = generation.message;
48884
+ const generationInfo = generation.generationInfo ?? {};
48885
+ const responseMetadata = message?.response_metadata ?? {};
48886
+ modelName = modelName || generationInfo.model || generationInfo.model_name || responseMetadata.model;
48887
+ modelProvider = modelProvider || generationInfo.model_provider || responseMetadata.model_provider;
48888
+ if (!message || message.getType() !== "ai") {
48889
+ if (!message && generation.text) {
48890
+ responses.push({ content: generation.text });
48891
+ }
48892
+ continue;
48893
+ }
48894
+ responses.push({ content: message.content });
48895
+ const usage = message.usage_metadata;
48896
+ if (usage) {
48897
+ inputTokens += usage.input_tokens ?? 0;
48898
+ outputTokens += usage.output_tokens ?? 0;
48899
+ totalTokens += usage.total_tokens ?? 0;
48900
+ hasUsage = true;
48901
+ }
48902
+ const messageToolCalls = message.tool_calls ?? [];
48903
+ for (const toolCall of messageToolCalls) {
48904
+ const announced = { tool_name: toolCall.name };
48905
+ const toolCallId = toolCall.id;
48906
+ if (toolCallId) {
48907
+ announced.tool_call_id = toolCallId;
48908
+ }
48909
+ toolCalls.push(announced);
48910
+ if (llmCallSpan !== null && toolCallId) {
48911
+ this.llmCallSpanIdByToolCallId.set(toolCallId, llmCallSpan.spanId);
48912
+ }
48913
+ }
48914
+ }
48915
+ }
48916
+ if (hasUsage) {
48917
+ this.session.recordTokenUsage({ inputTokens, outputTokens, totalTokens });
48918
+ }
48919
+ if (llmCallSpan !== null) {
48920
+ const responsesJson = responses.length > 0 ? this.safeJsonStringify(responses, "LLM responses") : null;
48921
+ const toolCallsJson = toolCalls.length > 0 ? this.safeJsonStringify(toolCalls, "LLM tool calls") : null;
48922
+ llmCallSpan.setAttributes({
48923
+ modelName,
48924
+ modelProvider,
48925
+ ...hasUsage ? { inputTokens, outputTokens, totalTokens } : {},
48926
+ ...responsesJson !== null ? { responsesJson } : {},
48927
+ ...toolCallsJson !== null ? { toolCallsJson } : {}
48928
+ });
48929
+ if (err !== null) {
48930
+ llmCallSpan.setAttributes({
48931
+ errorType: err.constructor.name,
48932
+ errorMessage: `${err}`
48933
+ });
48934
+ }
48935
+ }
48936
+ this.endSpan(runId);
48937
+ }
48938
+ stampLlmCallSpanId(span, toolCallId) {
48939
+ if (!toolCallId) {
48940
+ return;
48941
+ }
48942
+ const llmCallSpanId = this.llmCallSpanIdByToolCallId.get(toolCallId);
48943
+ if (llmCallSpanId !== undefined) {
48944
+ span.setAttributes({ llmCallSpanId });
48945
+ }
48946
+ this.llmCallSpanIdByToolCallId.delete(toolCallId);
48947
+ }
48948
+ endSpan(runId) {
48949
+ const span = this.spansByRunId.get(runId);
48950
+ if (span !== undefined) {
48951
+ span.end();
48952
+ this.spansByRunId.delete(runId);
48953
+ }
48954
+ }
48645
48955
  closeToolCallSpan({
48646
48956
  toolCallId,
48647
48957
  span,
@@ -49067,6 +49377,14 @@ class AccessTokenProvider {
49067
49377
  }
49068
49378
  }
49069
49379
 
49380
+ // src/core/redaction-options.ts
49381
+ function resolveRedactionOptions(options) {
49382
+ return {
49383
+ redactToolArgs: options?.redactToolArgs ?? false,
49384
+ redactAgentState: options?.redactAgentState ?? false
49385
+ };
49386
+ }
49387
+
49070
49388
  // src/core/sdk-attributes/detect-runtime.ts
49071
49389
  function detectRuntime() {
49072
49390
  const g = globalThis;
@@ -49107,7 +49425,7 @@ import { fileURLToPath } from "node:url";
49107
49425
 
49108
49426
  // src/generated/sdk-meta.ts
49109
49427
  var SDK_NAME = "@friskai/frisk-js";
49110
- var SDK_VERSION = "0.3.0";
49428
+ var SDK_VERSION = "0.3.1";
49111
49429
 
49112
49430
  // src/core/sdk-attributes/read-sdk-meta.ts
49113
49431
  function getSdkMeta() {
@@ -50331,5 +50649,5 @@ export {
50331
50649
  FRISK_SESSION_ID_KEY
50332
50650
  };
50333
50651
 
50334
- //# debugId=46F5000910B6966364756E2164756E21
50652
+ //# debugId=B3DA4933179DBD8B64756E2164756E21
50335
50653
  //# sourceMappingURL=index.js.map