@dexto/core 1.8.3 → 1.8.4

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 (51) hide show
  1. package/dist/agent/DextoAgent.cjs +3 -1
  2. package/dist/agent/DextoAgent.d.ts +2 -0
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +7 -2
  5. package/dist/events/index.d.ts +3 -0
  6. package/dist/events/index.d.ts.map +1 -1
  7. package/dist/index.browser.cjs +6 -0
  8. package/dist/index.browser.d.ts +2 -0
  9. package/dist/index.browser.d.ts.map +1 -1
  10. package/dist/index.browser.js +4 -0
  11. package/dist/llm/executor/provider-error.cjs +214 -0
  12. package/dist/llm/executor/provider-error.d.ts +26 -0
  13. package/dist/llm/executor/provider-error.d.ts.map +1 -0
  14. package/dist/llm/executor/provider-error.js +190 -0
  15. package/dist/llm/executor/stream-processor.cjs +34 -5
  16. package/dist/llm/executor/stream-processor.d.ts +4 -1
  17. package/dist/llm/executor/stream-processor.d.ts.map +1 -1
  18. package/dist/llm/executor/stream-processor.js +34 -5
  19. package/dist/llm/executor/turn-executor.cjs +185 -124
  20. package/dist/llm/executor/turn-executor.d.ts +5 -5
  21. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  22. package/dist/llm/executor/turn-executor.js +184 -120
  23. package/dist/session/title-generator.cjs +19 -2
  24. package/dist/session/title-generator.d.ts +8 -0
  25. package/dist/session/title-generator.d.ts.map +1 -1
  26. package/dist/session/title-generator.js +19 -2
  27. package/dist/systemPrompt/contributors.cjs +10 -1
  28. package/dist/systemPrompt/contributors.d.ts.map +1 -1
  29. package/dist/systemPrompt/contributors.js +10 -1
  30. package/dist/telemetry/browser.cjs +138 -0
  31. package/dist/telemetry/browser.d.ts +30 -0
  32. package/dist/telemetry/browser.d.ts.map +1 -0
  33. package/dist/telemetry/browser.js +115 -0
  34. package/dist/telemetry/index.cjs +5 -2
  35. package/dist/telemetry/index.d.ts +1 -0
  36. package/dist/telemetry/index.d.ts.map +1 -1
  37. package/dist/telemetry/index.js +3 -1
  38. package/dist/telemetry/operation-span.cjs +73 -0
  39. package/dist/telemetry/operation-span.d.ts +13 -0
  40. package/dist/telemetry/operation-span.d.ts.map +1 -0
  41. package/dist/telemetry/operation-span.js +50 -0
  42. package/dist/telemetry/telemetry.cjs +2 -3
  43. package/dist/telemetry/telemetry.d.ts.map +1 -1
  44. package/dist/telemetry/telemetry.js +2 -3
  45. package/dist/telemetry/utils.cjs +11 -12
  46. package/dist/telemetry/utils.d.ts.map +1 -1
  47. package/dist/telemetry/utils.js +11 -12
  48. package/dist/tools/tool-call-metadata.cjs +118 -6
  49. package/dist/tools/tool-call-metadata.d.ts.map +1 -1
  50. package/dist/tools/tool-call-metadata.js +118 -6
  51. package/package.json +2 -2
@@ -13,9 +13,11 @@ import { StreamProcessor } from "./stream-processor.js";
13
13
  import { truncateToolResult } from "./tool-output-truncator.js";
14
14
  import { buildProviderOptions, getEffectiveReasoningBudgetTokens } from "./provider-options.js";
15
15
  import { DextoLogComponent } from "../../logger/v2/types.js";
16
- import { DextoRuntimeError } from "../../errors/DextoRuntimeError.js";
17
- import { ErrorScope, ErrorType } from "../../errors/types.js";
18
- import { LLMErrorCode } from "../error-codes.js";
16
+ import { recordOperationSpan } from "../../telemetry/operation-span.js";
17
+ import {
18
+ extractProviderErrorDetails,
19
+ mapProviderError as mapCoreProviderError
20
+ } from "./provider-error.js";
19
21
  import { toError } from "../../utils/error-conversion.js";
20
22
  import { isCodexBaseURL } from "../providers/codex-base-url.js";
21
23
  import { createModelToolDefinitions } from "./tool-definitions.js";
@@ -350,11 +352,19 @@ class TurnExecutor {
350
352
  this.currentModelStepId = `in-memory-model-step-${stepCount}`;
351
353
  modelStepPreparing = true;
352
354
  try {
353
- preparedModelRequest = await this.prepareNextModelRequest({
354
- contributorContext,
355
- supportsTools: turn.supportsTools,
356
- streaming: options.streaming
357
- });
355
+ preparedModelRequest = await recordOperationSpan(
356
+ {
357
+ name: "turn.prepare_model_step",
358
+ componentName: "TurnExecutor",
359
+ attributes: { "turn.step_count": stepCount }
360
+ },
361
+ () => this.prepareNextModelRequest({
362
+ contributorContext,
363
+ supportsTools: turn.supportsTools,
364
+ streaming: options.streaming
365
+ }),
366
+ this.logger
367
+ );
358
368
  } catch (error) {
359
369
  currentStepScope[Symbol.dispose]();
360
370
  currentStepScope = null;
@@ -380,11 +390,19 @@ class TurnExecutor {
380
390
  }
381
391
  currentStepScope = this.startModelStepScope();
382
392
  this.currentModelStepId = `in-memory-model-step-${stepCount}`;
383
- preparedModelRequest = await this.prepareNextModelRequest({
384
- contributorContext,
385
- supportsTools: turn.supportsTools,
386
- streaming: options.streaming
387
- });
393
+ preparedModelRequest = await recordOperationSpan(
394
+ {
395
+ name: "turn.prepare_model_step",
396
+ componentName: "TurnExecutor",
397
+ attributes: { "turn.step_count": stepCount }
398
+ },
399
+ () => this.prepareNextModelRequest({
400
+ contributorContext,
401
+ supportsTools: turn.supportsTools,
402
+ streaming: options.streaming
403
+ }),
404
+ this.logger
405
+ );
388
406
  }
389
407
  const modelStepRequest = preparedModelRequest;
390
408
  if (currentStepScope === null || modelStepRequest === null) {
@@ -576,7 +594,13 @@ class TurnExecutor {
576
594
  this.eventBus.emit("llm:error", {
577
595
  error: mappedError,
578
596
  context: "TurnExecutor",
579
- recoverable: false
597
+ recoverable: false,
598
+ details: extractProviderErrorDetails({
599
+ error,
600
+ provider: this.llmContext.provider,
601
+ model: this.llmContext.model,
602
+ sessionId: this.sessionId
603
+ })
580
604
  });
581
605
  await this.contextManager.flush();
582
606
  this.eventBus.emit("run:complete", {
@@ -773,48 +797,159 @@ class TurnExecutor {
773
797
  await this.injectQueuedMessages(coalesced);
774
798
  }
775
799
  await this.pruneOldToolOutputs();
776
- let prepared = await this.contextManager.getFormattedMessagesForLLM(
777
- input.contributorContext,
778
- this.llmContext
800
+ let systemPrompt = await recordOperationSpan(
801
+ {
802
+ name: "system_prompt.build",
803
+ componentName: "TurnExecutor",
804
+ attributes: {
805
+ "llm.model": this.llmContext.model,
806
+ "llm.provider": this.llmContext.provider
807
+ }
808
+ },
809
+ () => this.contextManager.getSystemPrompt(input.contributorContext),
810
+ this.logger
779
811
  );
780
- const toolDefinitions = input.supportsTools ? this.toolManager.filterToolsForSession(
781
- await this.toolManager.getAllTools(),
782
- this.sessionId
812
+ let { preparedHistory, formattedMessages } = await recordOperationSpan(
813
+ {
814
+ name: "context.build_messages",
815
+ componentName: "TurnExecutor",
816
+ attributes: {
817
+ "llm.model": this.llmContext.model,
818
+ "llm.provider": this.llmContext.provider
819
+ }
820
+ },
821
+ async () => {
822
+ const preparedHistory2 = (await this.contextManager.prepareHistory()).preparedHistory;
823
+ const formattedMessages2 = await this.contextManager.getFormattedMessages(
824
+ input.contributorContext,
825
+ this.llmContext,
826
+ systemPrompt,
827
+ preparedHistory2
828
+ );
829
+ return { preparedHistory: preparedHistory2, formattedMessages: formattedMessages2 };
830
+ },
831
+ this.logger
832
+ );
833
+ const toolDefinitions = input.supportsTools ? await recordOperationSpan(
834
+ {
835
+ name: "tools.list",
836
+ componentName: "TurnExecutor",
837
+ attributes: { "tools.supports": input.supportsTools },
838
+ resultAttributes: (tools) => ({ "tools.count": Object.keys(tools).length })
839
+ },
840
+ async () => this.toolManager.filterToolsForSession(
841
+ await this.toolManager.getAllTools(),
842
+ this.sessionId
843
+ ),
844
+ this.logger
783
845
  ) : {};
784
- let estimatedInputTokens = await this.contextManager.getEstimatedNextInputTokens(
785
- prepared.systemPrompt,
786
- prepared.preparedHistory,
787
- toolDefinitions
846
+ let estimatedInputTokens = await recordOperationSpan(
847
+ {
848
+ name: "context.token_estimate",
849
+ componentName: "TurnExecutor",
850
+ attributes: { "tools.count": Object.keys(toolDefinitions).length },
851
+ resultAttributes: (tokens) => ({ "context.estimated_input_tokens": tokens })
852
+ },
853
+ () => this.contextManager.getEstimatedNextInputTokens(
854
+ systemPrompt,
855
+ preparedHistory,
856
+ toolDefinitions
857
+ ),
858
+ this.logger
788
859
  );
789
860
  if (this.shouldCompact(estimatedInputTokens)) {
790
861
  this.logger.debug(
791
862
  `Pre-check: estimated ${estimatedInputTokens} tokens exceeds threshold, compacting`
792
863
  );
793
- const didCompact = await this.compactContext(
794
- estimatedInputTokens,
795
- input.contributorContext,
796
- toolDefinitions
864
+ const didCompact = await recordOperationSpan(
865
+ {
866
+ name: "context.compact",
867
+ componentName: "TurnExecutor",
868
+ attributes: { "context.estimated_input_tokens": estimatedInputTokens }
869
+ },
870
+ () => this.compactContext(
871
+ estimatedInputTokens,
872
+ input.contributorContext,
873
+ toolDefinitions
874
+ ),
875
+ this.logger
797
876
  );
798
877
  if (didCompact) {
799
- prepared = await this.contextManager.getFormattedMessagesForLLM(
800
- input.contributorContext,
801
- this.llmContext
878
+ systemPrompt = await recordOperationSpan(
879
+ {
880
+ name: "system_prompt.build",
881
+ componentName: "TurnExecutor",
882
+ attributes: {
883
+ "context.after_compaction": true,
884
+ "llm.model": this.llmContext.model,
885
+ "llm.provider": this.llmContext.provider
886
+ }
887
+ },
888
+ () => this.contextManager.getSystemPrompt(input.contributorContext),
889
+ this.logger
802
890
  );
803
- estimatedInputTokens = await this.contextManager.getEstimatedNextInputTokens(
804
- prepared.systemPrompt,
805
- prepared.preparedHistory,
806
- toolDefinitions
891
+ ({ preparedHistory, formattedMessages } = await recordOperationSpan(
892
+ {
893
+ name: "context.build_messages",
894
+ componentName: "TurnExecutor",
895
+ attributes: {
896
+ "context.after_compaction": true,
897
+ "llm.model": this.llmContext.model,
898
+ "llm.provider": this.llmContext.provider
899
+ }
900
+ },
901
+ async () => {
902
+ const preparedHistory2 = (await this.contextManager.prepareHistory()).preparedHistory;
903
+ const formattedMessages2 = await this.contextManager.getFormattedMessages(
904
+ input.contributorContext,
905
+ this.llmContext,
906
+ systemPrompt,
907
+ preparedHistory2
908
+ );
909
+ return { preparedHistory: preparedHistory2, formattedMessages: formattedMessages2 };
910
+ },
911
+ this.logger
912
+ ));
913
+ estimatedInputTokens = await recordOperationSpan(
914
+ {
915
+ name: "context.token_estimate",
916
+ componentName: "TurnExecutor",
917
+ attributes: {
918
+ "context.after_compaction": true,
919
+ "tools.count": Object.keys(toolDefinitions).length
920
+ },
921
+ resultAttributes: (tokens) => ({
922
+ "context.estimated_input_tokens": tokens
923
+ })
924
+ },
925
+ () => this.contextManager.getEstimatedNextInputTokens(
926
+ systemPrompt,
927
+ preparedHistory,
928
+ toolDefinitions
929
+ ),
930
+ this.logger
807
931
  );
808
932
  this.logger.debug(
809
933
  `Post-compaction: recomputed estimate is ${estimatedInputTokens} tokens`
810
934
  );
811
935
  }
812
936
  }
813
- const providerOptions = buildProviderOptions({
814
- provider: this.llmContext.provider,
815
- model: this.llmContext.model,
816
- reasoning: this.config.reasoning
817
- });
937
+ const providerOptions = await recordOperationSpan(
938
+ {
939
+ name: "llm.request_setup",
940
+ componentName: "TurnExecutor",
941
+ attributes: {
942
+ "llm.model": this.llmContext.model,
943
+ "llm.provider": this.llmContext.provider
944
+ }
945
+ },
946
+ () => buildProviderOptions({
947
+ provider: this.llmContext.provider,
948
+ model: this.llmContext.model,
949
+ reasoning: this.config.reasoning
950
+ }),
951
+ this.logger
952
+ );
818
953
  this.logger.debug("LLM request options", {
819
954
  provider: this.llmContext.provider,
820
955
  model: this.llmContext.model,
@@ -831,7 +966,7 @@ class TurnExecutor {
831
966
  ...reasoningBudgetTokens !== void 0 && { reasoningBudgetTokens }
832
967
  } : void 0;
833
968
  return {
834
- messages: prepared.formattedMessages,
969
+ messages: formattedMessages,
835
970
  tools: input.supportsTools ? createModelToolDefinitions(toolDefinitions) : {},
836
971
  toolDefinitions,
837
972
  estimatedInputTokens,
@@ -862,7 +997,8 @@ class TurnExecutor {
862
997
  this.stepAbortController.signal,
863
998
  this.getStreamProcessorConfig(request.estimatedInputTokens, request.reasoning),
864
999
  this.logger,
865
- request.streaming
1000
+ request.streaming,
1001
+ false
866
1002
  );
867
1003
  return streamProcessor.process(
868
1004
  () => streamText({
@@ -1499,84 +1635,12 @@ class TurnExecutor {
1499
1635
  * Map provider errors to DextoRuntimeError.
1500
1636
  */
1501
1637
  mapProviderError(err) {
1502
- if (APICallError.isInstance?.(err)) {
1503
- const status = err.statusCode;
1504
- const headers = err.responseHeaders || {};
1505
- const retryAfter = headers["retry-after"] ? Number(headers["retry-after"]) : void 0;
1506
- const body = typeof err.responseBody === "string" ? err.responseBody : JSON.stringify(err.responseBody ?? "");
1507
- if (status === 402) {
1508
- let balance;
1509
- try {
1510
- const parsed = JSON.parse(body);
1511
- const msg = parsed?.error?.message || "";
1512
- const match = msg.match(/Balance:\s*\$?([\d.]+)/i);
1513
- if (match) {
1514
- balance = parseFloat(match[1]);
1515
- }
1516
- } catch {
1517
- }
1518
- return new DextoRuntimeError(
1519
- LLMErrorCode.INSUFFICIENT_CREDITS,
1520
- ErrorScope.LLM,
1521
- ErrorType.PAYMENT_REQUIRED,
1522
- `Insufficient Dexto credits${balance !== void 0 ? `. Balance: $${balance.toFixed(2)}` : ""}`,
1523
- {
1524
- sessionId: this.sessionId,
1525
- provider: this.llmContext.provider,
1526
- model: this.llmContext.model,
1527
- status,
1528
- balance,
1529
- body
1530
- },
1531
- "Run `dexto billing` to check your balance"
1532
- );
1533
- }
1534
- if (status === 429) {
1535
- return new DextoRuntimeError(
1536
- LLMErrorCode.RATE_LIMIT_EXCEEDED,
1537
- ErrorScope.LLM,
1538
- ErrorType.RATE_LIMIT,
1539
- `Rate limit exceeded${body ? ` - ${body}` : ""}`,
1540
- {
1541
- sessionId: this.sessionId,
1542
- provider: this.llmContext.provider,
1543
- model: this.llmContext.model,
1544
- status,
1545
- retryAfter,
1546
- body
1547
- }
1548
- );
1549
- }
1550
- if (status === 408) {
1551
- return new DextoRuntimeError(
1552
- LLMErrorCode.GENERATION_FAILED,
1553
- ErrorScope.LLM,
1554
- ErrorType.TIMEOUT,
1555
- `Provider timed out${body ? ` - ${body}` : ""}`,
1556
- {
1557
- sessionId: this.sessionId,
1558
- provider: this.llmContext.provider,
1559
- model: this.llmContext.model,
1560
- status,
1561
- body
1562
- }
1563
- );
1564
- }
1565
- return new DextoRuntimeError(
1566
- LLMErrorCode.GENERATION_FAILED,
1567
- ErrorScope.LLM,
1568
- ErrorType.THIRD_PARTY,
1569
- `Provider error ${status}${body ? ` - ${body}` : ""}`,
1570
- {
1571
- sessionId: this.sessionId,
1572
- provider: this.llmContext.provider,
1573
- model: this.llmContext.model,
1574
- status,
1575
- body
1576
- }
1577
- );
1578
- }
1579
- return toError(err, this.logger);
1638
+ return mapCoreProviderError({
1639
+ error: err,
1640
+ provider: this.llmContext.provider,
1641
+ model: this.llmContext.model,
1642
+ sessionId: this.sessionId
1643
+ });
1580
1644
  }
1581
1645
  }
1582
1646
  export {
@@ -53,9 +53,12 @@ async function generateSessionTitle(config, userText, logger, opts = {}) {
53
53
  });
54
54
  const processed = postProcessTitle(result.text);
55
55
  if (!processed) {
56
- return { error: "LLM returned empty title" };
56
+ return {
57
+ error: "LLM returned empty title",
58
+ usage: toSessionTitleTokenUsage(result.totalUsage)
59
+ };
57
60
  }
58
- return { title: processed };
61
+ return { title: processed, usage: toSessionTitleTokenUsage(result.totalUsage) };
59
62
  } catch (error) {
60
63
  if (controller?.signal.aborted) {
61
64
  return { timedOut: true, error: "Timed out while waiting for LLM response" };
@@ -68,6 +71,20 @@ async function generateSessionTitle(config, userText, logger, opts = {}) {
68
71
  }
69
72
  }
70
73
  }
74
+ function toSessionTitleTokenUsage(usage) {
75
+ const tokenUsage = {};
76
+ copyTokenUsageNumber(tokenUsage, "cachedInputTokens", usage.cachedInputTokens);
77
+ copyTokenUsageNumber(tokenUsage, "inputTokens", usage.inputTokens);
78
+ copyTokenUsageNumber(tokenUsage, "outputTokens", usage.outputTokens);
79
+ copyTokenUsageNumber(tokenUsage, "reasoningTokens", usage.reasoningTokens);
80
+ copyTokenUsageNumber(tokenUsage, "totalTokens", usage.totalTokens);
81
+ return tokenUsage;
82
+ }
83
+ function copyTokenUsageNumber(target, key, value) {
84
+ if (typeof value === "number" && Number.isFinite(value)) {
85
+ target[key] = value;
86
+ }
87
+ }
71
88
  function deriveHeuristicTitle(userText) {
72
89
  const sanitized = sanitizeUserText(userText, 120);
73
90
  if (!sanitized) return void 0;
@@ -1,10 +1,18 @@
1
1
  import type { ValidatedLLMConfig } from '../llm/schemas.js';
2
2
  import type { Logger } from '../logger/v2/types.js';
3
3
  import type { DextoProviderContext, LanguageModelFactory } from '../llm/services/types.js';
4
+ export interface GenerateSessionTitleTokenUsage {
5
+ cachedInputTokens?: number;
6
+ inputTokens?: number;
7
+ outputTokens?: number;
8
+ reasoningTokens?: number;
9
+ totalTokens?: number;
10
+ }
4
11
  export interface GenerateSessionTitleResult {
5
12
  title?: string;
6
13
  error?: string;
7
14
  timedOut?: boolean;
15
+ usage?: GenerateSessionTitleTokenUsage;
8
16
  }
9
17
  /**
10
18
  * Generate a concise title for a chat based on the first user message.
@@ -1 +1 @@
1
- {"version":3,"file":"title-generator.d.ts","sourceRoot":"","sources":["../../src/session/title-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAI3F,MAAM,WAAW,0BAA0B;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IACF,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACjB,GACP,OAAO,CAAC,0BAA0B,CAAC,CAgDrC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CA8BzE"}
1
+ {"version":3,"file":"title-generator.d.ts","sourceRoot":"","sources":["../../src/session/title-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAI3F,MAAM,WAAW,8BAA8B;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,8BAA8B,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IACF,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACjB,GACP,OAAO,CAAC,0BAA0B,CAAC,CAmDrC;AAsBD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CA8BzE"}
@@ -30,9 +30,12 @@ async function generateSessionTitle(config, userText, logger, opts = {}) {
30
30
  });
31
31
  const processed = postProcessTitle(result.text);
32
32
  if (!processed) {
33
- return { error: "LLM returned empty title" };
33
+ return {
34
+ error: "LLM returned empty title",
35
+ usage: toSessionTitleTokenUsage(result.totalUsage)
36
+ };
34
37
  }
35
- return { title: processed };
38
+ return { title: processed, usage: toSessionTitleTokenUsage(result.totalUsage) };
36
39
  } catch (error) {
37
40
  if (controller?.signal.aborted) {
38
41
  return { timedOut: true, error: "Timed out while waiting for LLM response" };
@@ -45,6 +48,20 @@ async function generateSessionTitle(config, userText, logger, opts = {}) {
45
48
  }
46
49
  }
47
50
  }
51
+ function toSessionTitleTokenUsage(usage) {
52
+ const tokenUsage = {};
53
+ copyTokenUsageNumber(tokenUsage, "cachedInputTokens", usage.cachedInputTokens);
54
+ copyTokenUsageNumber(tokenUsage, "inputTokens", usage.inputTokens);
55
+ copyTokenUsageNumber(tokenUsage, "outputTokens", usage.outputTokens);
56
+ copyTokenUsageNumber(tokenUsage, "reasoningTokens", usage.reasoningTokens);
57
+ copyTokenUsageNumber(tokenUsage, "totalTokens", usage.totalTokens);
58
+ return tokenUsage;
59
+ }
60
+ function copyTokenUsageNumber(target, key, value) {
61
+ if (typeof value === "number" && Number.isFinite(value)) {
62
+ target[key] = value;
63
+ }
64
+ }
48
65
  function deriveHeuristicTitle(userText) {
49
66
  const sanitized = sanitizeUserText(userText, 120);
50
67
  if (!sanitized) return void 0;
@@ -29,6 +29,7 @@ var import_promises = require("fs/promises");
29
29
  var import_path = require("path");
30
30
  var import_errors = require("./errors.js");
31
31
  var import_DextoRuntimeError = require("../errors/DextoRuntimeError.js");
32
+ var import_operation_span = require("../telemetry/operation-span.js");
32
33
  class StaticContributor {
33
34
  constructor(id, priority, content) {
34
35
  this.id = id;
@@ -203,7 +204,15 @@ class SkillsContributor {
203
204
  logger;
204
205
  async getContent(_context) {
205
206
  try {
206
- const skills = await this.skillManager.list();
207
+ const skills = await (0, import_operation_span.recordOperationSpan)(
208
+ {
209
+ name: "skills.list",
210
+ componentName: "SkillsContributor",
211
+ resultAttributes: (skills2) => ({ "skills.count": skills2.length })
212
+ },
213
+ () => this.skillManager.list(),
214
+ this.logger
215
+ );
207
216
  if (skills.length === 0) {
208
217
  return "";
209
218
  }
@@ -1 +1 @@
1
- {"version":3,"file":"contributors.d.ts","sourceRoot":"","sources":["../../src/systemPrompt/contributors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contributors.d.ts","sourceRoot":"","sources":["../../src/systemPrompt/contributors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAGhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,qBAAa,iBAAkB,YAAW,uBAAuB;IAElD,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE,MAAM;IACvB,OAAO,CAAC,OAAO;gBAFR,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EACf,OAAO,EAAE,MAAM;IAGrB,UAAU,CAAC,QAAQ,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;CAGzE;AAED,qBAAa,kBAAmB,YAAW,uBAAuB;IAEnD,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE,MAAM;IACvB,OAAO,CAAC,eAAe;gBAFhB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EACf,eAAe,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,OAAO,CAAC,MAAM,CAAC;IAG9E,UAAU,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;CAGxE;AAED,MAAM,WAAW,sBAAsB;IACnC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAC7C,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B;AAED,qBAAa,eAAgB,YAAW,uBAAuB;IAMhD,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE,MAAM;IACvB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IAPnB,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,MAAM,CAAS;gBAGZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE,sBAAsB,YAAK,EAC5C,MAAM,EAAE,MAAM;IAMZ,UAAU,CAAC,QAAQ,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;CA6FzE;AAED,MAAM,WAAW,wBAAwB;IACrC,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAClC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpC;AAED;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,uBAAuB;IAIlD,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE,MAAM;IACvB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,OAAO;IANnB,OAAO,CAAC,MAAM,CAAS;gBAGZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EACf,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,wBAAwB,YAAK,EAC9C,MAAM,EAAE,MAAM;IAQZ,UAAU,CAAC,QAAQ,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;CAmDzE;AAED;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,uBAAuB;IAIlD,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE,MAAM;IACvB,OAAO,CAAC,YAAY;IALxB,OAAO,CAAC,MAAM,CAAS;gBAGZ,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EACf,YAAY,EAAE,YAAY,EAClC,MAAM,EAAE,MAAM;IAMZ,UAAU,CAAC,QAAQ,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;CAuCzE"}
@@ -3,6 +3,7 @@ import { readFile, stat } from "fs/promises";
3
3
  import { resolve, extname } from "path";
4
4
  import { SystemPromptError } from "./errors.js";
5
5
  import { DextoRuntimeError } from "../errors/DextoRuntimeError.js";
6
+ import { recordOperationSpan } from "../telemetry/operation-span.js";
6
7
  class StaticContributor {
7
8
  constructor(id, priority, content) {
8
9
  this.id = id;
@@ -177,7 +178,15 @@ class SkillsContributor {
177
178
  logger;
178
179
  async getContent(_context) {
179
180
  try {
180
- const skills = await this.skillManager.list();
181
+ const skills = await recordOperationSpan(
182
+ {
183
+ name: "skills.list",
184
+ componentName: "SkillsContributor",
185
+ resultAttributes: (skills2) => ({ "skills.count": skills2.length })
186
+ },
187
+ () => this.skillManager.list(),
188
+ this.logger
189
+ );
181
190
  if (skills.length === 0) {
182
191
  return "";
183
192
  }
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var browser_exports = {};
20
+ __export(browser_exports, {
21
+ Telemetry: () => Telemetry
22
+ });
23
+ module.exports = __toCommonJS(browser_exports);
24
+ var import_api = require("@opentelemetry/api");
25
+ function isGlobalTelemetryLike(value) {
26
+ if (typeof value !== "object" || value === null) {
27
+ return false;
28
+ }
29
+ return typeof Reflect.get(value, "forceFlush") === "function" && typeof Reflect.get(value, "isInitialized") === "function" && typeof Reflect.get(value, "name") === "string" && typeof Reflect.get(value, "shutdown") === "function" && Reflect.get(value, "tracer") !== void 0;
30
+ }
31
+ class Telemetry {
32
+ tracer;
33
+ name;
34
+ _isInitialized;
35
+ _shutdownHandler;
36
+ static _initPromise;
37
+ constructor(config, options) {
38
+ const serviceName = config.serviceName ?? "dexto-service";
39
+ const tracerName = config.tracerName ?? serviceName;
40
+ this.name = serviceName;
41
+ this.tracer = import_api.trace.getTracer(tracerName);
42
+ this._shutdownHandler = options.shutdown;
43
+ this._isInitialized = options.initialized;
44
+ }
45
+ static async registerGlobal(options = {}) {
46
+ const existing = Telemetry.getGlobalInstance();
47
+ if (existing !== void 0) {
48
+ return existing;
49
+ }
50
+ if (Telemetry._initPromise !== void 0) {
51
+ return Telemetry._initPromise;
52
+ }
53
+ Telemetry._initPromise = Promise.resolve().then(() => {
54
+ const current = Telemetry.getGlobalInstance();
55
+ if (current !== void 0) {
56
+ return current;
57
+ }
58
+ const telemetry = new Telemetry(options.config ?? {}, {
59
+ initialized: options.initialized ?? true,
60
+ ...options.shutdown !== void 0 && { shutdown: options.shutdown }
61
+ });
62
+ Telemetry.setGlobalInstance(telemetry);
63
+ return telemetry;
64
+ });
65
+ return Telemetry._initPromise;
66
+ }
67
+ static getActiveSpan() {
68
+ return import_api.trace.getActiveSpan();
69
+ }
70
+ static get() {
71
+ const telemetry = Telemetry.getGlobalInstance();
72
+ if (telemetry === void 0) {
73
+ throw new Error("Telemetry not initialized. Call Telemetry.registerGlobal() first.");
74
+ }
75
+ return telemetry;
76
+ }
77
+ static hasGlobalInstance() {
78
+ return Telemetry.getGlobalInstance() !== void 0;
79
+ }
80
+ static async shutdownGlobal() {
81
+ const telemetry = Telemetry.getGlobalInstance();
82
+ if (telemetry !== void 0) {
83
+ await telemetry.shutdown();
84
+ }
85
+ Telemetry.setGlobalInstance(void 0);
86
+ Telemetry._initPromise = void 0;
87
+ }
88
+ static setBaggage(baggage, ctx = import_api.context.active()) {
89
+ const currentBaggage = Object.fromEntries(
90
+ import_api.propagation.getBaggage(ctx)?.getAllEntries() ?? []
91
+ );
92
+ return import_api.propagation.setBaggage(
93
+ ctx,
94
+ import_api.propagation.createBaggage({
95
+ ...currentBaggage,
96
+ ...baggage
97
+ })
98
+ );
99
+ }
100
+ static withContext(ctx, fn) {
101
+ return import_api.context.with(ctx, fn);
102
+ }
103
+ isInitialized() {
104
+ return this._isInitialized;
105
+ }
106
+ async forceFlush() {
107
+ const provider = import_api.trace.getTracerProvider();
108
+ const forceFlush = Reflect.get(provider, "forceFlush");
109
+ if (typeof forceFlush === "function") {
110
+ await Reflect.apply(forceFlush, provider, []);
111
+ }
112
+ }
113
+ async shutdown() {
114
+ try {
115
+ await this._shutdownHandler?.();
116
+ } finally {
117
+ this._isInitialized = false;
118
+ this._shutdownHandler = void 0;
119
+ Telemetry.setGlobalInstance(void 0);
120
+ Telemetry._initPromise = void 0;
121
+ }
122
+ }
123
+ static getGlobalInstance() {
124
+ const telemetry = Reflect.get(globalThis, "__TELEMETRY__");
125
+ return isGlobalTelemetryLike(telemetry) ? telemetry : void 0;
126
+ }
127
+ static setGlobalInstance(telemetry) {
128
+ if (telemetry === void 0) {
129
+ Reflect.deleteProperty(globalThis, "__TELEMETRY__");
130
+ return;
131
+ }
132
+ Reflect.set(globalThis, "__TELEMETRY__", telemetry);
133
+ }
134
+ }
135
+ // Annotate the CommonJS export names for ESM import in node:
136
+ 0 && (module.exports = {
137
+ Telemetry
138
+ });