@pranavraut033/ats-checker 0.1.0 → 1.0.0

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