@reconcrap/boss-recommend-mcp 1.3.8 → 1.3.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reconcrap/boss-recommend-mcp",
3
- "version": "1.3.8",
3
+ "version": "1.3.9",
4
4
  "description": "Unified MCP pipeline for recommend-page filtering and screening on Boss Zhipin",
5
5
  "keywords": [
6
6
  "boss",
@@ -57,6 +57,13 @@ function shouldContinue(summary, targetCount) {
57
57
  return summary.inspected < targetCount;
58
58
  }
59
59
 
60
+ function hasResumeRequestSentMessage(state = {}) {
61
+ const lastText = normalizeText(state?.lastText || '');
62
+ const recent = Array.isArray(state?.recent) ? state.recent : [];
63
+ if (lastText.includes('简历请求已发送')) return true;
64
+ return recent.some((item) => normalizeText(item).includes('简历请求已发送'));
65
+ }
66
+
60
67
  export class BossChatApp {
61
68
  constructor({
62
69
  page,
@@ -691,19 +698,30 @@ export class BossChatApp {
691
698
  await this.interaction.sleepRange(360, 120);
692
699
 
693
700
  this.logger.log('候选人通过,执行求简历动作。');
694
- await this.checkpoint();
695
- const messageBefore =
696
- typeof this.page.getResumeRequestMessageState === 'function'
697
- ? await this.page.getResumeRequestMessageState()
698
- : { ok: false, count: 0, lastText: '', recent: [] };
699
- const askResult = await this.page.clickAskResume();
700
- await this.interaction.sleepRange(460, 150);
701
- if (askResult?.alreadyRequested) {
702
- baseResult.requested = true;
703
- this.logger.log('求简历动作完成:alreadyRequested=true');
704
- } else {
701
+ const maxRequestAttempts = 3;
702
+ let requestSucceeded = false;
703
+ let lastAttempt = null;
704
+
705
+ for (let requestAttempt = 0; requestAttempt < maxRequestAttempts; requestAttempt += 1) {
705
706
  await this.checkpoint();
706
- const confirmResult = await this.page.clickConfirmRequestResume();
707
+ const messageBefore =
708
+ typeof this.page.getResumeRequestMessageState === 'function'
709
+ ? await this.page.getResumeRequestMessageState()
710
+ : { ok: false, count: 0, lastText: '', recent: [] };
711
+ const askResult = await this.page.clickAskResume();
712
+ await this.interaction.sleepRange(460, 150);
713
+
714
+ let confirmResult = {
715
+ confirmed: false,
716
+ requestedVerified: false,
717
+ assumedRequested: false,
718
+ uiState: null,
719
+ };
720
+ if (!askResult?.alreadyRequested) {
721
+ await this.checkpoint();
722
+ confirmResult = await this.page.clickConfirmRequestResume();
723
+ }
724
+
707
725
  let messageObserved = false;
708
726
  let messageAfter = null;
709
727
  if (typeof this.page.waitForResumeRequestMessage === 'function') {
@@ -712,29 +730,50 @@ export class BossChatApp {
712
730
  timeoutMs: 7000,
713
731
  pollMs: 260,
714
732
  });
715
- messageObserved = Boolean(messageCheck?.observed);
716
733
  messageAfter = messageCheck?.state || null;
734
+ messageObserved = Boolean(messageCheck?.observed) || hasResumeRequestSentMessage(messageAfter || {});
717
735
  }
718
736
 
719
- const requestedVerified =
720
- Boolean(confirmResult?.requestedVerified) ||
721
- Boolean(messageObserved);
722
- baseResult.requested = requestedVerified;
737
+ const requestedVerified = Boolean(messageObserved);
738
+ lastAttempt = {
739
+ attempt: requestAttempt + 1,
740
+ askResult,
741
+ confirmResult,
742
+ messageBefore,
743
+ messageAfter,
744
+ messageObserved,
745
+ requestedVerified,
746
+ };
747
+
723
748
  if (messageAfter) {
724
749
  baseResult.artifacts.resumeRequestMessageBefore = Number(messageBefore?.count || 0);
725
750
  baseResult.artifacts.resumeRequestMessageAfter = Number(messageAfter?.count || 0);
726
751
  baseResult.artifacts.resumeRequestMessageObserved = messageObserved;
727
752
  baseResult.artifacts.resumeRequestMessageLastText = String(messageAfter?.lastText || '');
728
753
  }
754
+
729
755
  this.logger.log(
730
- `求简历动作完成:confirmed=${Boolean(confirmResult?.confirmed)} | disabledOperateAsk=${Boolean(confirmResult?.uiState?.hasDisabledOperateAsk)} | verified=${requestedVerified} | messageObserved=${messageObserved} | assumed=${Boolean(confirmResult?.assumedRequested)}`,
756
+ `求简历动作检查:attempt=${requestAttempt + 1}/${maxRequestAttempts} | alreadyRequested=${Boolean(askResult?.alreadyRequested)} | confirmed=${Boolean(confirmResult?.confirmed)} | disabledOperateAsk=${Boolean(confirmResult?.uiState?.hasDisabledOperateAsk)} | messageObserved=${messageObserved} | verified=${requestedVerified} | assumed=${Boolean(confirmResult?.assumedRequested)}`,
731
757
  );
732
- if (!requestedVerified) {
733
- throw new Error(
734
- `REQUEST_RESUME_NOT_CONFIRMED(state=${JSON.stringify(confirmResult?.uiState || {})},messageBefore=${Number(messageBefore?.count || 0)},messageAfter=${Number(messageAfter?.count || 0)})`,
735
- );
758
+
759
+ if (requestedVerified) {
760
+ requestSucceeded = true;
761
+ break;
762
+ }
763
+
764
+ if (requestAttempt < maxRequestAttempts - 1) {
765
+ this.logger.log('未检测到“简历请求已发送”提示,重新发起求简历。');
766
+ await this.interaction.sleepRange(640, 180);
736
767
  }
737
768
  }
769
+
770
+ baseResult.requested = requestSucceeded;
771
+ if (!requestSucceeded) {
772
+ const confirmStateText = JSON.stringify(lastAttempt?.confirmResult?.uiState || {});
773
+ throw new Error(
774
+ `REQUEST_RESUME_MESSAGE_NOT_OBSERVED(state=${confirmStateText},messageBefore=${Number(lastAttempt?.messageBefore?.count || 0)},messageAfter=${Number(lastAttempt?.messageAfter?.count || 0)},attempts=${maxRequestAttempts})`,
775
+ );
776
+ }
738
777
  }
739
778
 
740
779
  await this.stateStore.record(baseResult.customerKey, baseResult, baseAliases);
@@ -2756,10 +2756,16 @@ export class BossChatPage {
2756
2756
  async waitForResumeRequestMessage({ baselineCount = 0, timeoutMs = 6500, pollMs = 260 } = {}) {
2757
2757
  const start = Date.now();
2758
2758
  let latest = null;
2759
+ const hasSentMessage = (state = {}) => {
2760
+ const lastText = String(state?.lastText || '');
2761
+ const recent = Array.isArray(state?.recent) ? state.recent : [];
2762
+ if (lastText.includes('简历请求已发送')) return true;
2763
+ return recent.some((item) => String(item || '').includes('简历请求已发送'));
2764
+ };
2759
2765
  while (Date.now() - start < timeoutMs) {
2760
2766
  const state = await this.getResumeRequestMessageState();
2761
2767
  latest = state;
2762
- if (state.count > baselineCount) {
2768
+ if (state.count > baselineCount || hasSentMessage(state)) {
2763
2769
  return {
2764
2770
  observed: true,
2765
2771
  state,