@pranavraut033/ats-checker 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -715,6 +715,519 @@ var SuggestionEngine = class {
715
715
  }
716
716
  };
717
717
 
718
+ // src/llm/llm.budget.ts
719
+ var LLMBudgetManager = class {
720
+ constructor(limits) {
721
+ this.callCount = 0;
722
+ this.totalTokensUsed = 0;
723
+ this.limits = limits;
724
+ }
725
+ /**
726
+ * Check if we can make a call with the given token estimate
727
+ * Throws if budget would be exceeded
728
+ */
729
+ assertCanCall(requestedTokens) {
730
+ if (this.callCount >= this.limits.maxCalls) {
731
+ throw new Error(
732
+ `LLM call limit exceeded: ${this.callCount}/${this.limits.maxCalls} calls used`
733
+ );
734
+ }
735
+ if (requestedTokens > this.limits.maxTokensPerCall) {
736
+ throw new Error(
737
+ `Requested tokens ${requestedTokens} exceeds per-call limit ${this.limits.maxTokensPerCall}`
738
+ );
739
+ }
740
+ if (this.totalTokensUsed + requestedTokens > this.limits.maxTotalTokens) {
741
+ throw new Error(
742
+ `Total token budget exceeded: ${this.totalTokensUsed + requestedTokens}/${this.limits.maxTotalTokens}`
743
+ );
744
+ }
745
+ }
746
+ /**
747
+ * Record actual token usage from a completed call
748
+ */
749
+ recordUsage(tokensUsed) {
750
+ this.callCount += 1;
751
+ this.totalTokensUsed += tokensUsed;
752
+ }
753
+ /**
754
+ * Get current budget state
755
+ */
756
+ getStats() {
757
+ return {
758
+ callsUsed: this.callCount,
759
+ callsRemaining: Math.max(0, this.limits.maxCalls - this.callCount),
760
+ tokensUsed: this.totalTokensUsed,
761
+ tokensRemaining: Math.max(0, this.limits.maxTotalTokens - this.totalTokensUsed),
762
+ totalCalls: this.limits.maxCalls,
763
+ totalTokens: this.limits.maxTotalTokens
764
+ };
765
+ }
766
+ /**
767
+ * Check if budget is exhausted
768
+ */
769
+ isExhausted() {
770
+ return this.callCount >= this.limits.maxCalls || this.totalTokensUsed >= this.limits.maxTotalTokens;
771
+ }
772
+ /**
773
+ * Reset budget (for testing)
774
+ */
775
+ reset() {
776
+ this.callCount = 0;
777
+ this.totalTokensUsed = 0;
778
+ }
779
+ };
780
+
781
+ // src/llm/llm.manager.ts
782
+ var LLMManager = class {
783
+ constructor(config) {
784
+ this.warnings = [];
785
+ this.config = config;
786
+ this.client = config.client;
787
+ this.budgetManager = new LLMBudgetManager(config.limits);
788
+ this.timeoutMs = config.timeoutMs ?? 3e4;
789
+ }
790
+ /**
791
+ * Structured call to LLM with timeout and budget protection
792
+ */
793
+ async callLLM(systemPrompt, userPrompt, schema, options = {}) {
794
+ try {
795
+ const estimatedTokens = this.estimateTokens(systemPrompt, userPrompt, options.requestedTokens);
796
+ try {
797
+ this.budgetManager.assertCanCall(estimatedTokens);
798
+ } catch (e) {
799
+ const msg = `LLM budget exhausted: ${e.message}`;
800
+ this.warnings.push(msg);
801
+ return { success: false, fallback: true, error: msg };
802
+ }
803
+ if (!this.isValidJsonSchema(schema)) {
804
+ const msg = "Invalid JSON schema provided";
805
+ this.warnings.push(msg);
806
+ return { success: false, fallback: true, error: msg };
807
+ }
808
+ const strictUserPrompt = `${userPrompt}
809
+
810
+ Return ONLY valid JSON matching the schema below.
811
+ No explanations. No markdown. No additional text.`;
812
+ const response = await Promise.race([
813
+ this.client.createCompletion({
814
+ model: options.useThinking ? this.config.models?.thinking || this.config.models?.default || "gpt-4o" : this.config.models?.default || "gpt-4o",
815
+ messages: [
816
+ { role: "system", content: systemPrompt },
817
+ { role: "user", content: strictUserPrompt }
818
+ ],
819
+ max_tokens: options.requestedTokens || 2e3,
820
+ response_format: schema
821
+ }),
822
+ this.createTimeout(this.timeoutMs)
823
+ ]);
824
+ if (!response || !response.content) {
825
+ return { success: false, fallback: true, error: "Empty response from LLM" };
826
+ }
827
+ let parsedContent;
828
+ try {
829
+ if (typeof response.content === "string") {
830
+ parsedContent = JSON.parse(response.content);
831
+ } else {
832
+ parsedContent = response.content;
833
+ }
834
+ } catch (e) {
835
+ const msg = `Invalid JSON in LLM response: ${e.message}`;
836
+ this.warnings.push(msg);
837
+ return { success: false, fallback: true, error: msg };
838
+ }
839
+ if (!this.validateAgainstSchema(parsedContent, schema)) {
840
+ const msg = "LLM response does not match schema";
841
+ this.warnings.push(msg);
842
+ return { success: false, fallback: true, error: msg };
843
+ }
844
+ const tokensUsed = response.usage?.total_tokens || estimatedTokens;
845
+ this.budgetManager.recordUsage(tokensUsed);
846
+ return {
847
+ success: true,
848
+ fallback: false,
849
+ data: parsedContent,
850
+ tokensUsed
851
+ };
852
+ } catch (e) {
853
+ const msg = `LLM call failed: ${e.message}`;
854
+ this.warnings.push(msg);
855
+ return { success: false, fallback: true, error: msg };
856
+ }
857
+ }
858
+ /**
859
+ * Get list of warnings from LLM operations
860
+ */
861
+ getWarnings() {
862
+ return [...this.warnings];
863
+ }
864
+ /**
865
+ * Get budget stats
866
+ */
867
+ getBudgetStats() {
868
+ return this.budgetManager.getStats();
869
+ }
870
+ /**
871
+ * Check if features are enabled
872
+ */
873
+ isFeatureEnabled(feature) {
874
+ return this.config.enable?.[feature] === true;
875
+ }
876
+ // ============ Private helpers ============
877
+ /**
878
+ * Create a timeout promise
879
+ */
880
+ createTimeout(ms) {
881
+ return new Promise((_, reject) => {
882
+ globalThis.setTimeout(() => reject(new Error(`LLM call timeout after ${ms}ms`)), ms);
883
+ });
884
+ }
885
+ /**
886
+ * Estimate tokens for a call (rough approximation)
887
+ * 1 token ≈ 4 characters average
888
+ */
889
+ estimateTokens(systemPrompt, userPrompt, requestedTokens) {
890
+ if (requestedTokens) {
891
+ return requestedTokens;
892
+ }
893
+ const totalChars = systemPrompt.length + userPrompt.length;
894
+ const estimatedInputTokens = Math.ceil(totalChars / 4);
895
+ return estimatedInputTokens + Math.ceil(estimatedInputTokens / 2);
896
+ }
897
+ /**
898
+ * Validate that schema looks like valid JSON schema
899
+ */
900
+ isValidJsonSchema(schema) {
901
+ return schema && schema.type === "object" && !!(schema.properties || schema.required);
902
+ }
903
+ /**
904
+ * Simple schema validation - check required fields exist
905
+ */
906
+ validateAgainstSchema(data, schema) {
907
+ if (typeof data !== "object" || data === null) {
908
+ return false;
909
+ }
910
+ const obj = data;
911
+ if (schema.required) {
912
+ for (const field of schema.required) {
913
+ if (!(field in obj)) {
914
+ return false;
915
+ }
916
+ }
917
+ }
918
+ return true;
919
+ }
920
+ };
921
+
922
+ // src/llm/llm.schemas.ts
923
+ var skillNormalizationSchema = {
924
+ type: "object",
925
+ properties: {
926
+ canonicalSkills: {
927
+ type: "array",
928
+ items: {
929
+ type: "object",
930
+ properties: {
931
+ input: {
932
+ type: "string",
933
+ description: "Original skill name from input"
934
+ },
935
+ normalized: {
936
+ type: "string",
937
+ description: "Canonical/normalized skill name"
938
+ },
939
+ confidence: {
940
+ type: "number",
941
+ description: "Confidence score 0-1 that this is correct"
942
+ }
943
+ },
944
+ required: ["input", "normalized"]
945
+ },
946
+ description: "Array of skill normalizations"
947
+ }
948
+ },
949
+ required: ["canonicalSkills"]
950
+ };
951
+ var sectionClassificationSchema = {
952
+ type: "object",
953
+ properties: {
954
+ sections: {
955
+ type: "array",
956
+ items: {
957
+ type: "object",
958
+ properties: {
959
+ header: {
960
+ type: "string",
961
+ description: "The section header text"
962
+ },
963
+ classification: {
964
+ type: "string",
965
+ enum: ["summary", "experience", "skills", "education", "projects", "certifications", "other"],
966
+ description: "Classified section type"
967
+ },
968
+ confidence: {
969
+ type: "number",
970
+ description: "Confidence 0-1 in the classification"
971
+ }
972
+ },
973
+ required: ["header", "classification"]
974
+ },
975
+ description: "Array of section classifications"
976
+ }
977
+ },
978
+ required: ["sections"]
979
+ };
980
+ var suggestionEnhancementSchema = {
981
+ type: "object",
982
+ properties: {
983
+ suggestions: {
984
+ type: "array",
985
+ items: {
986
+ type: "object",
987
+ properties: {
988
+ original: {
989
+ type: "string",
990
+ description: "Original suggestion from deterministic engine"
991
+ },
992
+ enhanced: {
993
+ type: "string",
994
+ description: "Improved phrasing of the suggestion"
995
+ },
996
+ actionable: {
997
+ type: "boolean",
998
+ description: "Whether the suggestion is concrete and actionable"
999
+ }
1000
+ },
1001
+ required: ["original", "enhanced"]
1002
+ },
1003
+ description: "Array of enhanced suggestions"
1004
+ }
1005
+ },
1006
+ required: ["suggestions"]
1007
+ };
1008
+ var jdClarificationSchema = {
1009
+ type: "object",
1010
+ properties: {
1011
+ implicitSkills: {
1012
+ type: "array",
1013
+ items: { type: "string" },
1014
+ description: "Skills implied but not explicitly mentioned"
1015
+ },
1016
+ implicitExperience: {
1017
+ type: "object",
1018
+ properties: {
1019
+ minYears: {
1020
+ type: "number",
1021
+ description: "Inferred minimum experience years"
1022
+ },
1023
+ domains: {
1024
+ type: "array",
1025
+ items: { type: "string" },
1026
+ description: "Industry domains implied"
1027
+ }
1028
+ },
1029
+ description: "Inferred experience requirements"
1030
+ },
1031
+ clarityScore: {
1032
+ type: "number",
1033
+ description: "0-1 score indicating JD clarity"
1034
+ }
1035
+ },
1036
+ required: ["implicitSkills", "clarityScore"]
1037
+ };
1038
+ var validationSchema = {
1039
+ type: "object",
1040
+ properties: {
1041
+ valid: {
1042
+ type: "boolean",
1043
+ description: "Whether the input is valid"
1044
+ },
1045
+ message: {
1046
+ type: "string",
1047
+ description: "Validation message"
1048
+ }
1049
+ },
1050
+ required: ["valid"]
1051
+ };
1052
+ var LLMSchemas = {
1053
+ skillNormalization: skillNormalizationSchema,
1054
+ sectionClassification: sectionClassificationSchema,
1055
+ suggestionEnhancement: suggestionEnhancementSchema,
1056
+ jdClarification: jdClarificationSchema,
1057
+ validation: validationSchema
1058
+ };
1059
+
1060
+ // src/llm/llm.prompts.ts
1061
+ var LLMPrompts = {
1062
+ /**
1063
+ * System prompt for skill normalization
1064
+ */
1065
+ skillNormalizationSystem: `You are a technical skill normalization expert.
1066
+ Your task is to normalize and canonicalize technical skill names.
1067
+ Handle aliases, abbreviations, and variations.
1068
+ Be conservative - only group skills that are genuinely synonymous.
1069
+ Return ONLY valid JSON.`,
1070
+ /**
1071
+ * User prompt for skill normalization
1072
+ */
1073
+ skillNormalizationUser: (skills) => `Normalize these skills:
1074
+ ${skills.map((s) => `- ${s}`).join("\n")}
1075
+
1076
+ Return the canonical names with confidence scores.`,
1077
+ /**
1078
+ * System prompt for section classification
1079
+ */
1080
+ sectionClassificationSystem: `You are a resume section classifier.
1081
+ Classify ambiguous section headers into standard resume categories.
1082
+ Be strict - if uncertain, classify as "other".
1083
+ Provide confidence scores.
1084
+ Return ONLY valid JSON.`,
1085
+ /**
1086
+ * User prompt for section classification
1087
+ */
1088
+ sectionClassificationUser: (headers) => `Classify these resume section headers:
1089
+ ${headers.map((h) => `- "${h}"`).join("\n")}
1090
+
1091
+ Use categories: summary, experience, skills, education, projects, certifications, other.`,
1092
+ /**
1093
+ * System prompt for suggestion enhancement
1094
+ */
1095
+ suggestionEnhancementSystem: `You are a resume advice expert.
1096
+ Improve suggestions to be more actionable and specific.
1097
+ Maintain the core message but make it more concrete.
1098
+ Return ONLY valid JSON.`,
1099
+ /**
1100
+ * User prompt for suggestion enhancement
1101
+ */
1102
+ suggestionEnhancementUser: (suggestions) => `Enhance these suggestions for clarity and actionability:
1103
+ ${suggestions.map((s) => `- ${s}`).join("\n")}
1104
+
1105
+ Make them specific and measurable where possible.`,
1106
+ /**
1107
+ * System prompt for JD clarification
1108
+ */
1109
+ jdClarificationSystem: `You are a job description analyzer.
1110
+ Extract implicit requirements not explicitly stated.
1111
+ Be conservative - stick to reasonable inferences.
1112
+ Rate the clarity of the job description.
1113
+ Return ONLY valid JSON.`,
1114
+ /**
1115
+ * User prompt for JD clarification
1116
+ */
1117
+ jdClarificationUser: (jd) => `Analyze this job description for implicit requirements:
1118
+
1119
+ ${jd}
1120
+
1121
+ What skills are implied but not explicitly mentioned?
1122
+ What experience domains are indicated?
1123
+ How clear is this job description (0-1)?`
1124
+ };
1125
+ function createPrompt(systemBase, userBuilder, input) {
1126
+ return {
1127
+ system: systemBase,
1128
+ user: userBuilder(input)
1129
+ };
1130
+ }
1131
+
1132
+ // src/llm/llm.adapters.ts
1133
+ function adaptSkillNormalizationResponse(data) {
1134
+ if (!data || typeof data !== "object") {
1135
+ return [];
1136
+ }
1137
+ const obj = data;
1138
+ const canonicalSkills = obj.canonicalSkills;
1139
+ if (!Array.isArray(canonicalSkills)) {
1140
+ return [];
1141
+ }
1142
+ const results = [];
1143
+ for (const item of canonicalSkills) {
1144
+ if (typeof item !== "object" || item === null) continue;
1145
+ const skill = item;
1146
+ const input = skill.input;
1147
+ const normalized = skill.normalized;
1148
+ const confidence = typeof skill.confidence === "number" ? skill.confidence : void 0;
1149
+ if (input && normalized) {
1150
+ results.push({ input, normalized, confidence });
1151
+ }
1152
+ }
1153
+ return results;
1154
+ }
1155
+ function adaptSectionClassificationResponse(data) {
1156
+ if (!data || typeof data !== "object") {
1157
+ return [];
1158
+ }
1159
+ const obj = data;
1160
+ const sections = obj.sections;
1161
+ if (!Array.isArray(sections)) {
1162
+ return [];
1163
+ }
1164
+ const results = [];
1165
+ for (const item of sections) {
1166
+ if (typeof item !== "object" || item === null) continue;
1167
+ const section = item;
1168
+ const header = section.header;
1169
+ const classification = section.classification;
1170
+ const confidence = typeof section.confidence === "number" ? section.confidence : void 0;
1171
+ if (header && classification) {
1172
+ results.push({ header, classification, confidence });
1173
+ }
1174
+ }
1175
+ return results;
1176
+ }
1177
+ function adaptSuggestionEnhancementResponse(data) {
1178
+ if (!data || typeof data !== "object") {
1179
+ return [];
1180
+ }
1181
+ const obj = data;
1182
+ const suggestions = obj.suggestions;
1183
+ if (!Array.isArray(suggestions)) {
1184
+ return [];
1185
+ }
1186
+ const results = [];
1187
+ for (const item of suggestions) {
1188
+ if (typeof item !== "object" || item === null) continue;
1189
+ const suggestion = item;
1190
+ const original = suggestion.original;
1191
+ const enhanced = suggestion.enhanced;
1192
+ const actionable = typeof suggestion.actionable === "boolean" ? suggestion.actionable : void 0;
1193
+ if (original && enhanced) {
1194
+ results.push({ original, enhanced, actionable });
1195
+ }
1196
+ }
1197
+ return results;
1198
+ }
1199
+ function adaptJdClarificationResponse(data) {
1200
+ if (!data || typeof data !== "object") {
1201
+ return { implicitSkills: [] };
1202
+ }
1203
+ const obj = data;
1204
+ const implicitSkills = Array.isArray(obj.implicitSkills) ? obj.implicitSkills.filter((s) => typeof s === "string") : [];
1205
+ const implicitExperience = obj.implicitExperience && typeof obj.implicitExperience === "object" ? obj.implicitExperience : void 0;
1206
+ const minYears = implicitExperience && typeof implicitExperience.minYears === "number" ? implicitExperience.minYears : void 0;
1207
+ const domains = implicitExperience && Array.isArray(implicitExperience.domains) ? implicitExperience.domains : void 0;
1208
+ const clarityScore = typeof obj.clarityScore === "number" ? obj.clarityScore : void 0;
1209
+ return {
1210
+ implicitSkills,
1211
+ implicitExperience: minYears || domains ? { minYears, domains } : void 0,
1212
+ clarityScore
1213
+ };
1214
+ }
1215
+ function safeExtractString(obj, key) {
1216
+ if (typeof obj !== "object" || obj === null) return void 0;
1217
+ const value = obj[key];
1218
+ return typeof value === "string" ? value : void 0;
1219
+ }
1220
+ function safeExtractArray(obj, key) {
1221
+ if (typeof obj !== "object" || obj === null) return [];
1222
+ const value = obj[key];
1223
+ return Array.isArray(value) ? value : [];
1224
+ }
1225
+ function safeExtractNumber(obj, key) {
1226
+ if (typeof obj !== "object" || obj === null) return void 0;
1227
+ const value = obj[key];
1228
+ return typeof value === "number" ? value : void 0;
1229
+ }
1230
+
718
1231
  // src/index.ts
719
1232
  function analyzeResume(input) {
720
1233
  const resolvedConfig = resolveConfig(input.config ?? {});
@@ -736,6 +1249,15 @@ function analyzeResume(input) {
736
1249
  score: scoring,
737
1250
  ruleWarnings: ruleResult.warnings
738
1251
  });
1252
+ let suggestions = suggestionResult.suggestions;
1253
+ const llmWarnings = [];
1254
+ if (input.llm && suggestionResult.suggestions.length > 0) {
1255
+ const llmResult = enhanceSuggestionsWithLLM(input.llm, suggestionResult.suggestions);
1256
+ if (llmResult.success) {
1257
+ suggestions = llmResult.enhancedSuggestions || suggestions;
1258
+ }
1259
+ llmWarnings.push(...llmResult.warnings);
1260
+ }
739
1261
  const finalScore = clamp(scoring.score - ruleResult.totalPenalty, 0, 100);
740
1262
  return {
741
1263
  score: finalScore,
@@ -743,11 +1265,105 @@ function analyzeResume(input) {
743
1265
  matchedKeywords: scoring.matchedKeywords,
744
1266
  missingKeywords: scoring.missingKeywords,
745
1267
  overusedKeywords: scoring.overusedKeywords,
746
- suggestions: suggestionResult.suggestions,
747
- warnings: suggestionResult.warnings
1268
+ suggestions,
1269
+ warnings: [...suggestionResult.warnings, ...llmWarnings]
748
1270
  };
749
1271
  }
1272
+ function enhanceSuggestionsWithLLM(config, suggestions) {
1273
+ if (!config.enable?.suggestions) {
1274
+ return { success: false, warnings: [] };
1275
+ }
1276
+ const warnings = [];
1277
+ try {
1278
+ const llmManager = new LLMManager(config);
1279
+ warnings.push(
1280
+ "LLM suggestion enhancement skipped - use async analyzeResumeAsync for LLM features"
1281
+ );
1282
+ return { success: false, warnings };
1283
+ } catch (e) {
1284
+ warnings.push(`Failed to enhance suggestions: ${e.message}`);
1285
+ return { success: false, warnings };
1286
+ }
1287
+ }
1288
+ async function analyzeResumeAsync(input) {
1289
+ const resolvedConfig = resolveConfig(input.config ?? {});
1290
+ const parsedResume = parseResume(input.resumeText, resolvedConfig);
1291
+ const parsedJob = parseJobDescription(input.jobDescription, resolvedConfig);
1292
+ const scoring = calculateScore(parsedResume, parsedJob, resolvedConfig);
1293
+ const ruleEngine = new RuleEngine(resolvedConfig);
1294
+ const ruleResult = ruleEngine.evaluate({
1295
+ resume: parsedResume,
1296
+ job: parsedJob,
1297
+ breakdown: scoring.breakdown,
1298
+ matchedKeywords: scoring.matchedKeywords,
1299
+ overusedKeywords: scoring.overusedKeywords
1300
+ });
1301
+ const suggestionEngine = new SuggestionEngine();
1302
+ const suggestionResult = suggestionEngine.generate({
1303
+ resume: parsedResume,
1304
+ job: parsedJob,
1305
+ score: scoring,
1306
+ ruleWarnings: ruleResult.warnings
1307
+ });
1308
+ let suggestions = suggestionResult.suggestions;
1309
+ const llmWarnings = [];
1310
+ if (input.llm && suggestionResult.suggestions.length > 0) {
1311
+ const llmResult = await enhanceSuggestionsWithLLMAsync(
1312
+ input.llm,
1313
+ suggestionResult.suggestions
1314
+ );
1315
+ if (llmResult.success) {
1316
+ suggestions = llmResult.enhancedSuggestions || suggestions;
1317
+ }
1318
+ llmWarnings.push(...llmResult.warnings);
1319
+ }
1320
+ const finalScore = clamp(scoring.score - ruleResult.totalPenalty, 0, 100);
1321
+ return {
1322
+ score: finalScore,
1323
+ breakdown: scoring.breakdown,
1324
+ matchedKeywords: scoring.matchedKeywords,
1325
+ missingKeywords: scoring.missingKeywords,
1326
+ overusedKeywords: scoring.overusedKeywords,
1327
+ suggestions,
1328
+ warnings: [...suggestionResult.warnings, ...llmWarnings]
1329
+ };
1330
+ }
1331
+ async function enhanceSuggestionsWithLLMAsync(config, suggestions) {
1332
+ if (!config.enable?.suggestions) {
1333
+ return { success: false, warnings: [] };
1334
+ }
1335
+ const warnings = [];
1336
+ try {
1337
+ const llmManager = new LLMManager(config);
1338
+ const result = await llmManager.callLLM(
1339
+ LLMPrompts.suggestionEnhancementSystem,
1340
+ LLMPrompts.suggestionEnhancementUser(suggestions),
1341
+ LLMSchemas.suggestionEnhancement,
1342
+ { requestedTokens: 2e3 }
1343
+ );
1344
+ if (!result.success || !result.data) {
1345
+ if (result.error) {
1346
+ warnings.push(`LLM suggestion enhancement failed: ${result.error}`);
1347
+ }
1348
+ return { success: false, warnings: [...warnings, ...llmManager.getWarnings()] };
1349
+ }
1350
+ const enhanced = adaptSuggestionEnhancementResponse(result.data);
1351
+ const enhancedSuggestions = enhanced.filter((e) => e.actionable !== false).map((e) => e.enhanced);
1352
+ if (enhancedSuggestions.length === 0) {
1353
+ warnings.push("LLM returned no actionable enhanced suggestions");
1354
+ return { success: false, warnings: [...warnings, ...llmManager.getWarnings()] };
1355
+ }
1356
+ return {
1357
+ success: true,
1358
+ enhancedSuggestions,
1359
+ warnings: llmManager.getWarnings()
1360
+ };
1361
+ } catch (e) {
1362
+ warnings.push(`Unexpected error in LLM enhancement: ${e.message}`);
1363
+ return { success: false, warnings };
1364
+ }
1365
+ }
750
1366
 
751
- export { analyzeResume, defaultProfiles, defaultSkillAliases };
1367
+ export { LLMBudgetManager, LLMManager, LLMPrompts, LLMSchemas, adaptJdClarificationResponse, adaptSectionClassificationResponse, adaptSkillNormalizationResponse, adaptSuggestionEnhancementResponse, analyzeResume, analyzeResumeAsync, createPrompt, defaultProfiles, defaultSkillAliases, safeExtractArray, safeExtractNumber, safeExtractString };
752
1368
  //# sourceMappingURL=index.mjs.map
753
1369
  //# sourceMappingURL=index.mjs.map