A form does not run out of steps repeating what changed nothing

Recorded on a real SmartRecruiters form: about 40 of 150 steps went on PageUp and a screenshot, in a form that scrolls inside its own container. The model is told not to repeat an action that changed nothing, and the plugin says how that form scrolls. On the next runs SmartRecruiters and Paylocity reached the send button; nothing was sent. Also the last mentions of the per-job CV.
This commit is contained in:
feder-cr committed 2026-11-05 19:34:37 +01:00
1 parent 2f342b721d
commit 7737d2293e
6 files changed
+9 -4

No files matched your search

+1
View File
@@ -18,6 +18,7 @@
- A form no longer stops to ask. The model fills every required field from what the CV says and implies, and a written field it has nothing for says to see the attached CV. - A form no longer stops to ask. The model fills every required field from what the CV says and implies, and a written field it has nothing for says to see the attached CV.
- The checks on the model's calls are gone, for far less code: it is told not to send, and nothing holds it to that. See SECURITY.md. - The checks on the model's calls are gone, for far less code: it is told not to send, and nothing holds it to that. See SECURITY.md.
- Less to carry: your own CV goes with every form, in place of one written for each job, and there is one gateway, one key variable and one folder. - Less to carry: your own CV goes with every form, in place of one written for each job, and there is one gateway, one key variable and one folder.
- A form no longer runs out of steps pressing a key that scrolls nothing: the model is told not to repeat what changed nothing.
- What goes wrong in the browser now reaches the screen as itself, a refused key included, in place of "unhandled errors in a TaskGroup". A page that says nothing yet after the send is read again when it changes, and a click that breaks is never called failed, because it may have gone. - What goes wrong in the browser now reaches the screen as itself, a refused key included, in place of "unhandled errors in a TaskGroup". A page that says nothing yet after the send is read again when it changes, and a click that breaks is never called failed, because it may have gone.
- Every posting is tried. A plugin helps the model where there is one, and there is no list of sites AIHawk will not touch. - Every posting is tried. A plugin helps the model where there is one, and there is no list of sites AIHawk will not touch.
- A setting of the wrong type in `aihawk.yaml` is one plain line instead of a traceback. - A setting of the wrong type in `aihawk.yaml` is one plain line instead of a traceback.
+1 -1
View File
@@ -10,7 +10,7 @@ Loading a resume rewrites this file, and the rewrite drops the comments you put
| `goals` | empty | What you are looking for, in your own words. The decision model and the judge read it. | | `goals` | empty | What you are looking for, in your own words. The decision model and the judge read it. |
| `database` | `https://github.com/feder-cr/Jobs_Applier_AI_Agent/releases/download/jobs-latest/manifest.json` | Where the job database is: the URL of its `manifest.json`, or the path of a local one. The files it names sit beside it, unless its `base_url` says otherwise. | | `database` | `https://github.com/feder-cr/Jobs_Applier_AI_Agent/releases/download/jobs-latest/manifest.json` | Where the job database is: the URL of its `manifest.json`, or the path of a local one. The files it names sit beside it, unless its `base_url` says otherwise. |
| `max_age_days` | `60` | Postings posted more than this many days ago are left out. A posting with no date is kept. | | `max_age_days` | `60` | Postings posted more than this many days ago are left out. A posting with no date is kept. |
| `model` | `deepseek/deepseek-v4.1-flash` | Writes the tailored CV and fills the application forms. | | `model` | `deepseek/deepseek-v4.1-flash` | Fills the application forms. |
| `quick_model` | `google/gemini-3.5-flash` | Writes the search plan from your CV, and the other short calls of a search. | | `quick_model` | `google/gemini-3.5-flash` | Writes the search plan from your CV, and the other short calls of a search. |
| `judge_model` | `deepseek/deepseek-v4.1-flash` | Writes the score and the report of each shortlisted posting. | | `judge_model` | `deepseek/deepseek-v4.1-flash` | Writes the score and the report of each shortlisted posting. |
| `decision_model` | `typesafe/jev-1.14` | Jev, which answers the six questions that shortlist the postings. | | `decision_model` | `typesafe/jev-1.14` | Jev, which answers the six questions that shortlist the postings. |
+2 -2
View File
@@ -10,11 +10,11 @@ What AIHawk can do on each site, from the real forms it has been run on. Posting
| JazzHR (applytojob.com) | ~154k | stops at a captcha most of the time | reCAPTCHA did not pass with a click on 5 postings; it often turned into an image puzzle. | | JazzHR (applytojob.com) | ~154k | stops at a captcha most of the time | reCAPTCHA did not pass with a click on 5 postings; it often turned into an image puzzle. |
| BambooHR (bamboohr.com) | ~87k | stops at a captcha most of the time | reCAPTCHA did not pass with a click on 5 postings; it often turned into an image puzzle. | | BambooHR (bamboohr.com) | ~87k | stops at a captcha most of the time | reCAPTCHA did not pass with a click on 5 postings; it often turned into an image puzzle. |
| Personio (jobs.personio.de, jobs.personio.com) | ~64k | stops at a captcha about half the time | Turnstile passed on 2 of 4 postings. A real form ended blocked. | | Personio (jobs.personio.de, jobs.personio.com) | ~64k | stops at a captcha about half the time | Turnstile passed on 2 of 4 postings. A real form ended blocked. |
| SmartRecruiters (jobs.smartrecruiters.com) | ~519k | reaches the send button, not always | One real form filled through every step in about 11 minutes, and the send button named. Later runs on the same form did not get there: one failed on an error, one stopped at 150 steps. No send has gone. | | SmartRecruiters (jobs.smartrecruiters.com) | ~519k | reaches the send button, not always | One real form filled through every step in about 11 minutes, and the send button named. A later run stopped at 150 steps, pressing keys that scrolled nothing; with a rule against that, the next run reached the button in about 10 minutes. No send has gone. |
| Recruitee (recruitee.com) | ~26k | sent and confirmed on a real form | One real send (one send only). Other forms stopped at required questions that test answers do not fit. | | Recruitee (recruitee.com) | ~26k | sent and confirmed on a real form | One real send (one send only). Other forms stopped at required questions that test answers do not fit. |
| Teamtailor (teamtailor.com) | ~30k | sent and confirmed on a real form | One real send (one send only). An earlier click was refused for its test phone number, so nothing went then. Other forms stopped at required questions. | | Teamtailor (teamtailor.com) | ~30k | sent and confirmed on a real form | One real send (one send only). An earlier click was refused for its test phone number, so nothing went then. Other forms stopped at required questions. |
| Workable (apply.workable.com) | ~35k | send clicked, not confirmed | One real form filled and sent: the button stayed on "Submitting…" beside an unticked Cloudflare box, and the browser was closed with no answer from the page. | | Workable (apply.workable.com) | ~35k | send clicked, not confirmed | One real form filled and sent: the button stayed on "Submitting…" beside an unticked Cloudflare box, and the browser was closed with no answer from the page. |
| Paylocity (recruiting.paylocity.com) | ~228k | reaches the send button, not always | One real form of 5 steps filled in about 27 minutes, and the send button named. A later run stopped at 150 steps. No send has gone. | | Paylocity (recruiting.paylocity.com) | ~228k | reaches the send button, not always | One real form of 5 steps filled in about 27 minutes, and the send button named. A later run stopped at 150 steps, and the next one reached the button in about 10 minutes. No send has gone. |
| Breezy (breezy.hr) | ~50k | sent and confirmed on a real form | One real send (one send only). | | Breezy (breezy.hr) | ~50k | sent and confirmed on a real form | One real send (one send only). |
| Workday (myworkdayjobs.com, myworkdaysite.com) | ~1,481k | tried, no plugin | Needs an account on each company's site: a form stops at the sign-in unless you are signed in. Not tried on a real form. | | Workday (myworkdayjobs.com, myworkdaysite.com) | ~1,481k | tried, no plugin | Needs an account on each company's site: a form stops at the sign-in unless you are signed in. Not tried on a real form. |
| iCIMS (icims.com) | ~622k | tried, no plugin | Needs an account: a form stops at the sign-in unless you are signed in. Not tried on a real form. | | iCIMS (icims.com) | ~622k | tried, no plugin | Needs an account: a form stops at the sign-in unless you are signed in. Not tried on a real form. |
+2
View File
@@ -73,6 +73,8 @@ You fill in one job application form in a browser, for the candidate, from the C
on it. on it.
- Do not send the application yourself. When every required field is filled, call finish_form with status ready and the - Do not send the application yourself. When every required field is filled, call finish_form with status ready and the
CSS selector of the submit control. CSS selector of the submit control.
- An action that leaves the page as it was will not work the second time: never repeat it, do something else. A key that
scrolls nothing means the form scrolls inside its own container: read and reach its fields with browser_evaluate.
- A captcha shown as a box to tick: click it. A puzzle or image challenge, a login wall or a closed posting: call - A captcha shown as a box to tick: click it. A puzzle or image challenge, a login wall or a closed posting: call
finish_form with status blocked. finish_form with status blocked.
- A code or confirmation link sent by email may be fetched as the instructions for that site say. - A code or confirmation link sent by email may be fetched as the instructions for that site say.
+2
View File
@@ -18,6 +18,8 @@ Menus (the country list, City suggestions, a dropdown's answers) open a list und
The footer "Next" button has no selector in browser_snapshot: read its centre the same way (browser_evaluate reads, then browser_click_at). Leave "Add" under Experience and Education alone unless the page requires an entry: "Please provide at least one work experience entry" under Experience means it does. Then add one from the CV: Title, Company and Office location suggest as you type, and From and To take MM/YYYY. The footer "Next" button has no selector in browser_snapshot: read its centre the same way (browser_evaluate reads, then browser_click_at). Leave "Add" under Experience and Education alone unless the page requires an entry: "Please provide at least one work experience entry" under Experience means it does. Then add one from the CV: Title, Company and Office location suggest as you type, and From and To take MM/YYYY.
The form scrolls inside its own container, so PageUp and PageDown move nothing: seen on a real form, 40 steps lost pressing them. To reach a field, call its `scrollIntoView()` with browser_evaluate, walking the shadow roots.
The "Preliminary questions" step often asks for the right to work, sponsorship, and a block of required boxes with the person's name and today's date, stating that the answers are true. The "Preliminary questions" step often asks for the right to work, sponsorship, and a block of required boxes with the person's name and today's date, stating that the answers are true.
The last step's footer control sends the application: `[data-test='footer-submit']`, labelled "Submit". Its label is what the page says, for example "Submit application". Never click it. If a plain CSS selector matches only that control, name it as the submit control; if none does, call finish_form with status blocked and say that the send control could not be named. The last step's footer control sends the application: `[data-test='footer-submit']`, labelled "Submit". Its label is what the page says, for example "Submit application". Never click it. If a plain CSS selector matches only that control, name it as the submit control; if none does, call finish_form with status blocked and say that the send control could not be named.
+1 -1
View File
@@ -508,7 +508,7 @@ class AIHawk(App[None]):
("places", "Where", ", ".join(config.filters.locations)), ("places", "Where", ", ".join(config.filters.locations)),
("exclude", "Leave out", ", ".join(config.filters.exclude)), ("exclude", "Leave out", ", ".join(config.filters.exclude)),
("max_age_days", "Posted within (days)", str(config.max_age_days)), ("max_age_days", "Posted within (days)", str(config.max_age_days)),
("model", "Forms and CVs model", config.model), ("model", "Forms model", config.model),
("judge_model", "Scoring model", config.judge_model), ("judge_model", "Scoring model", config.judge_model),
("quick_model", "Search plan model", config.quick_model), ("quick_model", "Search plan model", config.quick_model),
("decision_model", "Shortlist model", config.decision_model), ("decision_model", "Shortlist model", config.decision_model),