@dexto/core 1.8.3 → 1.8.5

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 (63) 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 +320 -152
  20. package/dist/llm/executor/turn-executor.d.ts +6 -5
  21. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  22. package/dist/llm/executor/turn-executor.js +319 -148
  23. package/dist/llm/registry/sync.cjs +15 -2
  24. package/dist/llm/registry/sync.d.ts.map +1 -1
  25. package/dist/llm/registry/sync.js +15 -2
  26. package/dist/llm/services/vercel.cjs +32 -5
  27. package/dist/llm/services/vercel.d.ts.map +1 -1
  28. package/dist/llm/services/vercel.js +32 -5
  29. package/dist/session/chat-session.cjs +41 -11
  30. package/dist/session/chat-session.d.ts.map +1 -1
  31. package/dist/session/chat-session.js +41 -11
  32. package/dist/session/title-generator.cjs +19 -2
  33. package/dist/session/title-generator.d.ts +8 -0
  34. package/dist/session/title-generator.d.ts.map +1 -1
  35. package/dist/session/title-generator.js +19 -2
  36. package/dist/systemPrompt/contributors.cjs +10 -1
  37. package/dist/systemPrompt/contributors.d.ts.map +1 -1
  38. package/dist/systemPrompt/contributors.js +10 -1
  39. package/dist/telemetry/browser.cjs +138 -0
  40. package/dist/telemetry/browser.d.ts +30 -0
  41. package/dist/telemetry/browser.d.ts.map +1 -0
  42. package/dist/telemetry/browser.js +115 -0
  43. package/dist/telemetry/decorators.cjs +86 -82
  44. package/dist/telemetry/decorators.d.ts.map +1 -1
  45. package/dist/telemetry/decorators.js +86 -82
  46. package/dist/telemetry/index.cjs +5 -2
  47. package/dist/telemetry/index.d.ts +1 -0
  48. package/dist/telemetry/index.d.ts.map +1 -1
  49. package/dist/telemetry/index.js +3 -1
  50. package/dist/telemetry/operation-span.cjs +74 -0
  51. package/dist/telemetry/operation-span.d.ts +13 -0
  52. package/dist/telemetry/operation-span.d.ts.map +1 -0
  53. package/dist/telemetry/operation-span.js +51 -0
  54. package/dist/telemetry/telemetry.cjs +2 -3
  55. package/dist/telemetry/telemetry.d.ts.map +1 -1
  56. package/dist/telemetry/telemetry.js +2 -3
  57. package/dist/telemetry/utils.cjs +11 -12
  58. package/dist/telemetry/utils.d.ts.map +1 -1
  59. package/dist/telemetry/utils.js +11 -12
  60. package/dist/tools/tool-call-metadata.cjs +121 -6
  61. package/dist/tools/tool-call-metadata.d.ts.map +1 -1
  62. package/dist/tools/tool-call-metadata.js +121 -6
  63. package/package.json +3 -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: this.createTurnStepSpanAttributes(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,18 +390,39 @@ 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: this.createTurnStepSpanAttributes(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) {
391
409
  throw new Error("Model step request was not prepared");
392
410
  }
393
411
  this.logger.debug(`Step ${stepCount}: Starting`);
394
- const result = await this.runModelStepWithRetry(modelStepRequest);
412
+ const result = await recordOperationSpan(
413
+ {
414
+ name: "turn.run_model_step",
415
+ componentName: "TurnExecutor",
416
+ attributes: this.createTurnStepSpanAttributes(stepCount),
417
+ resultAttributes: (stepResult) => ({
418
+ "llm.finish_reason": stepResult.finishReason,
419
+ "llm.output_text_length": stepResult.text.length,
420
+ "tool.count": stepResult.toolCalls.length
421
+ })
422
+ },
423
+ () => this.runModelStepWithRetry(modelStepRequest),
424
+ this.logger
425
+ );
395
426
  currentResult = result;
396
427
  currentToolCallsExecuted = result.finishReason !== "tool-calls";
397
428
  preparedModelRequest = null;
@@ -430,7 +461,18 @@ class TurnExecutor {
430
461
  toolCallsRunning = true;
431
462
  currentToolCallsExecuted = true;
432
463
  try {
433
- await this.executeModelToolCalls(result.toolCalls);
464
+ await recordOperationSpan(
465
+ {
466
+ name: "turn.execute_tool_calls",
467
+ componentName: "TurnExecutor",
468
+ attributes: {
469
+ ...this.createTurnStepSpanAttributes(stepCount),
470
+ "tool.count": result.toolCalls.length
471
+ }
472
+ },
473
+ () => this.executeModelToolCalls(result.toolCalls),
474
+ this.logger
475
+ );
434
476
  } catch (error) {
435
477
  currentToolCallsExecuted = false;
436
478
  throw error;
@@ -451,7 +493,23 @@ class TurnExecutor {
451
493
  if (result.finishReason === "tool-calls" && !currentToolCallsExecuted) {
452
494
  throw new Error("Tool calls must finish before deciding the next model step");
453
495
  }
454
- const nextStep = await this.decideNextStep(result, stepCount);
496
+ const nextStep = await recordOperationSpan(
497
+ {
498
+ name: "turn.decide_next_step",
499
+ componentName: "TurnExecutor",
500
+ attributes: {
501
+ ...this.createTurnStepSpanAttributes(stepCount),
502
+ "llm.finish_reason": result.finishReason,
503
+ "tool.calls_executed": currentToolCallsExecuted
504
+ },
505
+ resultAttributes: (decision) => ({
506
+ "turn.next_action": decision.kind,
507
+ "turn.next_step_count": decision.stepCount
508
+ })
509
+ },
510
+ () => this.decideNextStep(result, stepCount),
511
+ this.logger
512
+ );
455
513
  stepCount = nextStep.stepCount;
456
514
  currentResult = null;
457
515
  currentToolCallsExecuted = false;
@@ -555,6 +613,13 @@ class TurnExecutor {
555
613
  }
556
614
  };
557
615
  }
616
+ createTurnStepSpanAttributes(stepCount) {
617
+ return {
618
+ "turn.step_count": stepCount,
619
+ "llm.model": this.llmContext.model,
620
+ "llm.provider": this.llmContext.provider
621
+ };
622
+ }
558
623
  async finishTurn(input) {
559
624
  await this.contextManager.flush();
560
625
  this.setTelemetryAttributes(input.usage);
@@ -576,7 +641,13 @@ class TurnExecutor {
576
641
  this.eventBus.emit("llm:error", {
577
642
  error: mappedError,
578
643
  context: "TurnExecutor",
579
- recoverable: false
644
+ recoverable: false,
645
+ details: extractProviderErrorDetails({
646
+ error,
647
+ provider: this.llmContext.provider,
648
+ model: this.llmContext.model,
649
+ sessionId: this.sessionId
650
+ })
580
651
  });
581
652
  await this.contextManager.flush();
582
653
  this.eventBus.emit("run:complete", {
@@ -773,48 +844,159 @@ class TurnExecutor {
773
844
  await this.injectQueuedMessages(coalesced);
774
845
  }
775
846
  await this.pruneOldToolOutputs();
776
- let prepared = await this.contextManager.getFormattedMessagesForLLM(
777
- input.contributorContext,
778
- this.llmContext
847
+ let systemPrompt = await recordOperationSpan(
848
+ {
849
+ name: "system_prompt.build",
850
+ componentName: "TurnExecutor",
851
+ attributes: {
852
+ "llm.model": this.llmContext.model,
853
+ "llm.provider": this.llmContext.provider
854
+ }
855
+ },
856
+ () => this.contextManager.getSystemPrompt(input.contributorContext),
857
+ this.logger
779
858
  );
780
- const toolDefinitions = input.supportsTools ? this.toolManager.filterToolsForSession(
781
- await this.toolManager.getAllTools(),
782
- this.sessionId
859
+ let { preparedHistory, formattedMessages } = await recordOperationSpan(
860
+ {
861
+ name: "context.build_messages",
862
+ componentName: "TurnExecutor",
863
+ attributes: {
864
+ "llm.model": this.llmContext.model,
865
+ "llm.provider": this.llmContext.provider
866
+ }
867
+ },
868
+ async () => {
869
+ const preparedHistory2 = (await this.contextManager.prepareHistory()).preparedHistory;
870
+ const formattedMessages2 = await this.contextManager.getFormattedMessages(
871
+ input.contributorContext,
872
+ this.llmContext,
873
+ systemPrompt,
874
+ preparedHistory2
875
+ );
876
+ return { preparedHistory: preparedHistory2, formattedMessages: formattedMessages2 };
877
+ },
878
+ this.logger
879
+ );
880
+ const toolDefinitions = input.supportsTools ? await recordOperationSpan(
881
+ {
882
+ name: "tools.list",
883
+ componentName: "TurnExecutor",
884
+ attributes: { "tools.supports": input.supportsTools },
885
+ resultAttributes: (tools) => ({ "tools.count": Object.keys(tools).length })
886
+ },
887
+ async () => this.toolManager.filterToolsForSession(
888
+ await this.toolManager.getAllTools(),
889
+ this.sessionId
890
+ ),
891
+ this.logger
783
892
  ) : {};
784
- let estimatedInputTokens = await this.contextManager.getEstimatedNextInputTokens(
785
- prepared.systemPrompt,
786
- prepared.preparedHistory,
787
- toolDefinitions
893
+ let estimatedInputTokens = await recordOperationSpan(
894
+ {
895
+ name: "context.token_estimate",
896
+ componentName: "TurnExecutor",
897
+ attributes: { "tools.count": Object.keys(toolDefinitions).length },
898
+ resultAttributes: (tokens) => ({ "context.estimated_input_tokens": tokens })
899
+ },
900
+ () => this.contextManager.getEstimatedNextInputTokens(
901
+ systemPrompt,
902
+ preparedHistory,
903
+ toolDefinitions
904
+ ),
905
+ this.logger
788
906
  );
789
907
  if (this.shouldCompact(estimatedInputTokens)) {
790
908
  this.logger.debug(
791
909
  `Pre-check: estimated ${estimatedInputTokens} tokens exceeds threshold, compacting`
792
910
  );
793
- const didCompact = await this.compactContext(
794
- estimatedInputTokens,
795
- input.contributorContext,
796
- toolDefinitions
911
+ const didCompact = await recordOperationSpan(
912
+ {
913
+ name: "context.compact",
914
+ componentName: "TurnExecutor",
915
+ attributes: { "context.estimated_input_tokens": estimatedInputTokens }
916
+ },
917
+ () => this.compactContext(
918
+ estimatedInputTokens,
919
+ input.contributorContext,
920
+ toolDefinitions
921
+ ),
922
+ this.logger
797
923
  );
798
924
  if (didCompact) {
799
- prepared = await this.contextManager.getFormattedMessagesForLLM(
800
- input.contributorContext,
801
- this.llmContext
925
+ systemPrompt = await recordOperationSpan(
926
+ {
927
+ name: "system_prompt.build",
928
+ componentName: "TurnExecutor",
929
+ attributes: {
930
+ "context.after_compaction": true,
931
+ "llm.model": this.llmContext.model,
932
+ "llm.provider": this.llmContext.provider
933
+ }
934
+ },
935
+ () => this.contextManager.getSystemPrompt(input.contributorContext),
936
+ this.logger
802
937
  );
803
- estimatedInputTokens = await this.contextManager.getEstimatedNextInputTokens(
804
- prepared.systemPrompt,
805
- prepared.preparedHistory,
806
- toolDefinitions
938
+ ({ preparedHistory, formattedMessages } = await recordOperationSpan(
939
+ {
940
+ name: "context.build_messages",
941
+ componentName: "TurnExecutor",
942
+ attributes: {
943
+ "context.after_compaction": true,
944
+ "llm.model": this.llmContext.model,
945
+ "llm.provider": this.llmContext.provider
946
+ }
947
+ },
948
+ async () => {
949
+ const preparedHistory2 = (await this.contextManager.prepareHistory()).preparedHistory;
950
+ const formattedMessages2 = await this.contextManager.getFormattedMessages(
951
+ input.contributorContext,
952
+ this.llmContext,
953
+ systemPrompt,
954
+ preparedHistory2
955
+ );
956
+ return { preparedHistory: preparedHistory2, formattedMessages: formattedMessages2 };
957
+ },
958
+ this.logger
959
+ ));
960
+ estimatedInputTokens = await recordOperationSpan(
961
+ {
962
+ name: "context.token_estimate",
963
+ componentName: "TurnExecutor",
964
+ attributes: {
965
+ "context.after_compaction": true,
966
+ "tools.count": Object.keys(toolDefinitions).length
967
+ },
968
+ resultAttributes: (tokens) => ({
969
+ "context.estimated_input_tokens": tokens
970
+ })
971
+ },
972
+ () => this.contextManager.getEstimatedNextInputTokens(
973
+ systemPrompt,
974
+ preparedHistory,
975
+ toolDefinitions
976
+ ),
977
+ this.logger
807
978
  );
808
979
  this.logger.debug(
809
980
  `Post-compaction: recomputed estimate is ${estimatedInputTokens} tokens`
810
981
  );
811
982
  }
812
983
  }
813
- const providerOptions = buildProviderOptions({
814
- provider: this.llmContext.provider,
815
- model: this.llmContext.model,
816
- reasoning: this.config.reasoning
817
- });
984
+ const providerOptions = await recordOperationSpan(
985
+ {
986
+ name: "llm.request_setup",
987
+ componentName: "TurnExecutor",
988
+ attributes: {
989
+ "llm.model": this.llmContext.model,
990
+ "llm.provider": this.llmContext.provider
991
+ }
992
+ },
993
+ () => buildProviderOptions({
994
+ provider: this.llmContext.provider,
995
+ model: this.llmContext.model,
996
+ reasoning: this.config.reasoning
997
+ }),
998
+ this.logger
999
+ );
818
1000
  this.logger.debug("LLM request options", {
819
1001
  provider: this.llmContext.provider,
820
1002
  model: this.llmContext.model,
@@ -831,7 +1013,7 @@ class TurnExecutor {
831
1013
  ...reasoningBudgetTokens !== void 0 && { reasoningBudgetTokens }
832
1014
  } : void 0;
833
1015
  return {
834
- messages: prepared.formattedMessages,
1016
+ messages: formattedMessages,
835
1017
  tools: input.supportsTools ? createModelToolDefinitions(toolDefinitions) : {},
836
1018
  toolDefinitions,
837
1019
  estimatedInputTokens,
@@ -862,31 +1044,49 @@ class TurnExecutor {
862
1044
  this.stepAbortController.signal,
863
1045
  this.getStreamProcessorConfig(request.estimatedInputTokens, request.reasoning),
864
1046
  this.logger,
865
- request.streaming
1047
+ request.streaming,
1048
+ false
866
1049
  );
867
- return streamProcessor.process(
868
- () => streamText({
869
- model: this.model,
870
- stopWhen: stepCountIs(1),
871
- maxRetries: 0,
872
- tools: request.tools,
873
- abortSignal: this.stepAbortController.signal,
874
- messages: request.messages,
875
- ...this.config.maxOutputTokens !== void 0 && {
876
- maxOutputTokens: this.config.maxOutputTokens
877
- },
878
- ...this.config.temperature !== void 0 && {
879
- temperature: this.config.temperature
880
- },
881
- // Provider-specific options (caching, reasoning, etc.)
882
- ...request.providerOptions !== void 0 && {
883
- providerOptions: request.providerOptions
1050
+ return recordOperationSpan(
1051
+ {
1052
+ name: "llm.stream",
1053
+ componentName: "TurnExecutor",
1054
+ attributes: {
1055
+ "llm.model": this.llmContext.model,
1056
+ "llm.provider": this.llmContext.provider,
1057
+ "tools.count": Object.keys(request.toolDefinitions).length
884
1058
  },
885
- // Log stream-level errors (tool errors, API errors during streaming)
886
- onError: (error) => {
887
- this.logger.error("Stream error", { error });
888
- }
889
- })
1059
+ resultAttributes: (result) => ({
1060
+ "llm.finish_reason": result.finishReason,
1061
+ "llm.output_text_length": result.text.length,
1062
+ "tool.count": result.toolCalls.length
1063
+ })
1064
+ },
1065
+ () => streamProcessor.process(
1066
+ () => streamText({
1067
+ model: this.model,
1068
+ stopWhen: stepCountIs(1),
1069
+ maxRetries: 0,
1070
+ tools: request.tools,
1071
+ abortSignal: this.stepAbortController.signal,
1072
+ messages: request.messages,
1073
+ ...this.config.maxOutputTokens !== void 0 && {
1074
+ maxOutputTokens: this.config.maxOutputTokens
1075
+ },
1076
+ ...this.config.temperature !== void 0 && {
1077
+ temperature: this.config.temperature
1078
+ },
1079
+ // Provider-specific options (caching, reasoning, etc.)
1080
+ ...request.providerOptions !== void 0 && {
1081
+ providerOptions: request.providerOptions
1082
+ },
1083
+ // Log stream-level errors (tool errors, API errors during streaming)
1084
+ onError: (error) => {
1085
+ this.logger.error("Stream error", { error });
1086
+ }
1087
+ })
1088
+ ),
1089
+ this.logger
890
1090
  );
891
1091
  }
892
1092
  async runModelStepWithRetry(request) {
@@ -959,10 +1159,41 @@ class TurnExecutor {
959
1159
  async executeModelToolCalls(toolCalls) {
960
1160
  const preparedCalls = [];
961
1161
  for (const toolCall of toolCalls) {
962
- preparedCalls.push(await this.prepareModelToolCall(toolCall));
1162
+ preparedCalls.push(
1163
+ await recordOperationSpan(
1164
+ {
1165
+ name: "tool.prepare",
1166
+ componentName: "TurnExecutor",
1167
+ attributes: {
1168
+ "tool.call_id": toolCall.toolCallId,
1169
+ "tool.name": toolCall.toolName
1170
+ },
1171
+ resultAttributes: (prepared) => ({ "tool.prepare_kind": prepared.kind })
1172
+ },
1173
+ () => this.prepareModelToolCall(toolCall),
1174
+ this.logger
1175
+ )
1176
+ );
963
1177
  }
964
1178
  const executionResults = await Promise.all(
965
- preparedCalls.map((prepared) => this.executePreparedModelToolCall(prepared))
1179
+ preparedCalls.map(
1180
+ (prepared) => recordOperationSpan(
1181
+ {
1182
+ name: "tool.execute",
1183
+ componentName: "TurnExecutor",
1184
+ attributes: {
1185
+ "tool.call_id": prepared.toolCall.toolCallId,
1186
+ "tool.name": prepared.toolCall.toolName,
1187
+ "tool.prepare_kind": prepared.kind
1188
+ },
1189
+ resultAttributes: (result) => ({
1190
+ "tool.success": this.isToolExecutionSuccessful(result)
1191
+ })
1192
+ },
1193
+ () => this.executePreparedModelToolCall(prepared),
1194
+ this.logger
1195
+ )
1196
+ )
966
1197
  );
967
1198
  for (let index = 0; index < toolCalls.length; index += 1) {
968
1199
  const toolCall = toolCalls[index];
@@ -970,7 +1201,19 @@ class TurnExecutor {
970
1201
  if (toolCall === void 0 || executionResult === void 0) {
971
1202
  throw new Error("Tool call result count must match emitted tool call count");
972
1203
  }
973
- await this.persistModelToolResult(toolCall, executionResult);
1204
+ await recordOperationSpan(
1205
+ {
1206
+ name: "tool.persist_result",
1207
+ componentName: "TurnExecutor",
1208
+ attributes: {
1209
+ "tool.call_id": toolCall.toolCallId,
1210
+ "tool.name": toolCall.toolName,
1211
+ "tool.success": this.isToolExecutionSuccessful(executionResult)
1212
+ }
1213
+ },
1214
+ () => this.persistModelToolResult(toolCall, executionResult),
1215
+ this.logger
1216
+ );
974
1217
  }
975
1218
  }
976
1219
  async prepareModelToolCall(toolCall) {
@@ -1499,84 +1742,12 @@ class TurnExecutor {
1499
1742
  * Map provider errors to DextoRuntimeError.
1500
1743
  */
1501
1744
  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);
1745
+ return mapCoreProviderError({
1746
+ error: err,
1747
+ provider: this.llmContext.provider,
1748
+ model: this.llmContext.model,
1749
+ sessionId: this.sessionId
1750
+ });
1580
1751
  }
1581
1752
  }
1582
1753
  export {
@@ -257,6 +257,19 @@ function buildModelsFromModelsDevProvider(params) {
257
257
  results.sort((a, b) => a.name.localeCompare(b.name));
258
258
  return results;
259
259
  }
260
+ function hasProviderMetadata(model) {
261
+ return model.providerMetadata != null && Object.keys(model.providerMetadata).length > 0;
262
+ }
263
+ function dedupeModelsByNamePreferProviderMetadata(models) {
264
+ const byName = /* @__PURE__ */ new Map();
265
+ for (const model of models) {
266
+ const existing = byName.get(model.name);
267
+ if (!existing || !hasProviderMetadata(existing) && hasProviderMetadata(model)) {
268
+ byName.set(model.name, model);
269
+ }
270
+ }
271
+ return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
272
+ }
260
273
  function buildModelsByProviderFromParsedSources(params) {
261
274
  const { modelsDevApi } = params;
262
275
  const defaults = {
@@ -368,7 +381,7 @@ function buildModelsByProviderFromParsedSources(params) {
368
381
  }),
369
382
  litellm: [],
370
383
  glama: [],
371
- vertex: [
384
+ vertex: dedupeModelsByNamePreferProviderMetadata([
372
385
  ...buildModelsFromModelsDevProvider({
373
386
  spec: {
374
387
  provider: "vertex",
@@ -386,7 +399,7 @@ function buildModelsByProviderFromParsedSources(params) {
386
399
  },
387
400
  modelsDevApi
388
401
  })
389
- ].sort((a, b) => a.name.localeCompare(b.name)),
402
+ ]),
390
403
  bedrock: buildModelsFromModelsDevProvider({
391
404
  spec: {
392
405
  provider: "bedrock",
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/llm/registry/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,eAAO,MAAM,cAAc,gCAAgC,CAAC;AAE5D,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AACtD,KAAK,iBAAiB,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC1C,CAAC;AACF,KAAK,cAAc,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE;QACP,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChD,KAAK,EAAE;QACH,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,CAAC,EACL;QACI,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC;QAC3D,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC;KAC/D,GACD,SAAS,CAAC;IAChB,IAAI,CAAC,EACC;QACI,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,iBAAiB,CAAC,EAAE;YAChB,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,GACD,SAAS,CAAC;CACnB,CAAC;AA2CF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CA6J7D;AAmKD,wBAAgB,sCAAsC,CAAC,MAAM,EAAE;IAC3D,YAAY,EAAE,YAAY,CAAC;CAC9B,GAAG,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAuJnC;AAED,wBAAsB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAoB5C"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/llm/registry/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,eAAO,MAAM,cAAc,gCAAgC,CAAC;AAE5D,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AACtD,KAAK,iBAAiB,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC1C,CAAC;AACF,KAAK,cAAc,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE;QACP,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChD,KAAK,EAAE;QACH,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,CAAC,EACL;QACI,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC;QAC3D,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC;KAC/D,GACD,SAAS,CAAC;IAChB,IAAI,CAAC,EACC;QACI,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,iBAAiB,CAAC,EAAE;YAChB,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,GACD,SAAS,CAAC;CACnB,CAAC;AA2CF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CA6J7D;AAoLD,wBAAgB,sCAAsC,CAAC,MAAM,EAAE;IAC3D,YAAY,EAAE,YAAY,CAAC;CAC9B,GAAG,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAuJnC;AAED,wBAAsB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAoB5C"}
@@ -232,6 +232,19 @@ function buildModelsFromModelsDevProvider(params) {
232
232
  results.sort((a, b) => a.name.localeCompare(b.name));
233
233
  return results;
234
234
  }
235
+ function hasProviderMetadata(model) {
236
+ return model.providerMetadata != null && Object.keys(model.providerMetadata).length > 0;
237
+ }
238
+ function dedupeModelsByNamePreferProviderMetadata(models) {
239
+ const byName = /* @__PURE__ */ new Map();
240
+ for (const model of models) {
241
+ const existing = byName.get(model.name);
242
+ if (!existing || !hasProviderMetadata(existing) && hasProviderMetadata(model)) {
243
+ byName.set(model.name, model);
244
+ }
245
+ }
246
+ return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
247
+ }
235
248
  function buildModelsByProviderFromParsedSources(params) {
236
249
  const { modelsDevApi } = params;
237
250
  const defaults = {
@@ -343,7 +356,7 @@ function buildModelsByProviderFromParsedSources(params) {
343
356
  }),
344
357
  litellm: [],
345
358
  glama: [],
346
- vertex: [
359
+ vertex: dedupeModelsByNamePreferProviderMetadata([
347
360
  ...buildModelsFromModelsDevProvider({
348
361
  spec: {
349
362
  provider: "vertex",
@@ -361,7 +374,7 @@ function buildModelsByProviderFromParsedSources(params) {
361
374
  },
362
375
  modelsDevApi
363
376
  })
364
- ].sort((a, b) => a.name.localeCompare(b.name)),
377
+ ]),
365
378
  bedrock: buildModelsFromModelsDevProvider({
366
379
  spec: {
367
380
  provider: "bedrock",