localagentbrowser 1.57__tar.gz → 1.62__tar.gz

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 (42) hide show
  1. {localagentbrowser-1.57 → localagentbrowser-1.62}/CHANGELOG.md +60 -2
  2. {localagentbrowser-1.57 → localagentbrowser-1.62}/MANIFEST.in +1 -0
  3. {localagentbrowser-1.57/localagentbrowser.egg-info → localagentbrowser-1.62}/PKG-INFO +55 -26
  4. {localagentbrowser-1.57 → localagentbrowser-1.62}/README.md +54 -25
  5. localagentbrowser-1.62/agent_browser.py +23 -0
  6. localagentbrowser-1.62/localagentbrowser/__init__.py +26 -0
  7. localagentbrowser-1.62/localagentbrowser/agent.py +406 -0
  8. localagentbrowser-1.62/localagentbrowser/checklist.py +93 -0
  9. localagentbrowser-1.62/localagentbrowser/checks.py +248 -0
  10. localagentbrowser-1.62/localagentbrowser/config.py +96 -0
  11. localagentbrowser-1.62/localagentbrowser/coverage.py +175 -0
  12. localagentbrowser-1.62/localagentbrowser/grounding.py +121 -0
  13. localagentbrowser-1.62/localagentbrowser/pages.py +396 -0
  14. localagentbrowser-1.62/localagentbrowser/prompts.py +104 -0
  15. localagentbrowser-1.62/localagentbrowser/report.py +208 -0
  16. localagentbrowser-1.62/localagentbrowser/text.py +54 -0
  17. {localagentbrowser-1.57 → localagentbrowser-1.62/localagentbrowser.egg-info}/PKG-INFO +55 -26
  18. {localagentbrowser-1.57 → localagentbrowser-1.62}/localagentbrowser.egg-info/SOURCES.txt +13 -0
  19. localagentbrowser-1.62/localagentbrowser.egg-info/entry_points.txt +2 -0
  20. localagentbrowser-1.62/localagentbrowser.egg-info/top_level.txt +2 -0
  21. {localagentbrowser-1.57 → localagentbrowser-1.62}/pyproject.toml +3 -2
  22. localagentbrowser-1.62/tests/golden/prompts.json +2288 -0
  23. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_checklist.py +103 -8
  24. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_decisions.py +3 -2
  25. localagentbrowser-1.62/tests/test_golden_prompts.py +133 -0
  26. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_journal.py +7 -0
  27. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_main_loop.py +6 -5
  28. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_model_turns.py +2 -1
  29. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_page_text.py +16 -2
  30. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_regression.py +6 -0
  31. {localagentbrowser-1.57 → localagentbrowser-1.62}/tools/live_test.py +3 -2
  32. {localagentbrowser-1.57 → localagentbrowser-1.62}/tools/regression.py +4 -1
  33. localagentbrowser-1.57/agent_browser.py +0 -1658
  34. localagentbrowser-1.57/localagentbrowser.egg-info/entry_points.txt +0 -2
  35. localagentbrowser-1.57/localagentbrowser.egg-info/top_level.txt +0 -1
  36. {localagentbrowser-1.57 → localagentbrowser-1.62}/LICENSE +0 -0
  37. {localagentbrowser-1.57 → localagentbrowser-1.62}/localagentbrowser.egg-info/dependency_links.txt +0 -0
  38. {localagentbrowser-1.57 → localagentbrowser-1.62}/localagentbrowser.egg-info/requires.txt +0 -0
  39. {localagentbrowser-1.57 → localagentbrowser-1.62}/setup.cfg +0 -0
  40. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/conftest.py +0 -0
  41. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/fakes.py +0 -0
  42. {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_duplicates.py +0 -0
@@ -1,11 +1,69 @@
1
1
  # Changelog
2
2
 
3
- Every version of `agent_browser.py`, newest first. Each released version is also a tagged commit (`v1.11` … `v1.57`); 1.54 to 1.56 were internal steps
4
- measured on the regression suite and released as part of 1.57 (see
3
+ Every version of LocalAgentBrowser, newest first. Each released version is also a tagged commit (`v1.11` … `v1.62`); 1.54 to 1.56 and 1.58 to 1.60 were internal steps
4
+ measured on the regression suite and released as part of 1.57 and 1.61 (see
5
5
  [docs/regression-history.md](docs/regression-history.md)).
6
6
  Timings are from live runs on the development machine (Intel i5-9500, 6 cores, no GPU, Qwen2.5-7B-Instruct
7
7
  Q4_K_M in LM Studio), where reading the prompt takes about 90% of every model call.
8
8
 
9
+ ## [1.62] - 2026-10-25
10
+ No change in what the agent does: the same prompts, decisions and results as 1.61.
11
+ ### Changed
12
+ - The code is now a package, `localagentbrowser`, with one file per job (settings, prompts, page reading,
13
+ grounding, checklist, coverage, checks, report, and the loop) instead of one 1,805-line `agent_browser.py`. The
14
+ code was moved, not rewritten: every line of the old file is in the package once, in its original order with its
15
+ comments. `python agent_browser.py`, the `localagentbrowser` command and `import agent_browser` work as before.
16
+ The README's Code layout section says which file holds what.
17
+ ### Added
18
+ - Golden prompts (`tests/test_golden_prompts.py`): five scripted runs, including one through the outline pointer,
19
+ a refusal of a finding not on the page, a coverage send-back with a fresh prompt and caveats, compared character
20
+ for character with a recorded copy of every message sent to the model, the journal and the report. It was
21
+ recorded before the move and passed unchanged after it; a one-word change to a check's wording makes it fail and
22
+ name the model call that differs.
23
+
24
+ Regression run on the reorganized code: 7 of 7 finished (168.3 model minutes), against 6 of 7 (222.1) on 1.61. With
25
+ the same behaviour this is run-to-run variation (the documentation task finished in 5 turns this time), not an
26
+ improvement; each task's first prompt was identical to 1.61's, and every check still fired where its path came up.
27
+
28
+ ## [1.61] - 2026-10-21
29
+ Released together with the internal steps 1.58, 1.59 and 1.60, each measured on the regression suite
30
+ ([docs/regression-history.md](docs/regression-history.md) has every step's results, task by task).
31
+ ### Added
32
+ - An outline pointer for long pages. On a page long enough to have an outline, the read-on check looks for an unread
33
+ part whose label names a word of an item with nothing recorded yet ("Administration" for "setup and
34
+ administration"), and a plain READ_MORE then reads that part instead of the next one. Told only to use the
35
+ outline, the model went on to the next part 6 times out of 6 on a 10-part comparison page; with the code making
36
+ the jump, it reaches the part every time. Words that say what the whole page is about are ignored (the page title's
37
+ words, words every item shares), as are item verbs and parts that start inside code; hyphenated words stay whole.
38
+ On 1.61 the comparison finished for the first time since 1.56, from that page's Administration part.
39
+ - "Every item has the discoveries it asks for: choose FINISH now" in the note after a discovery, when each item has
40
+ at least what it asks for. When that holds, the read-on check also asks for FINISH instead of offering to read on
41
+ (replayed: read on 6 of 6 before, FINISH 9 of 9 after).
42
+ ### Changed
43
+ - The agent is sent back before finishing only for gaps the code verifies: an item nothing was copied for, fewer
44
+ things than the item asks for, or nothing recorded. The model's other verdicts are logged "(not sent back)" and
45
+ only shape the final result. About half of the send-backs for those verdicts had been wrong, costing finishes.
46
+ - Every item that asks for a number is counted, not only items with a condition: an owl task finished with two
47
+ tribes for "at least three cultures". Amounts of time or measure ("the first two weeks") are not counts.
48
+ - A thing not shown to meet a condition stays in the result, marked where it is first named ("**OnlyOffice** (not
49
+ shown in the pages read to be free and open-source)"), instead of being left out: leaving such things out dropped
50
+ correct answers along with wrong ones.
51
+ - A description named by the coverage check as one of a list's things is ignored (it had made two office suites
52
+ count as three).
53
+ - Smaller fresh prompts: refusal reasons in the journal are cut to 120 characters, pages list 8 links instead of 15
54
+ (those with a few words of text first; in four suites the agent opened 39 pages, none from page links), and links
55
+ whose text is HTML are skipped. Fresh prompts are about 2,500 tokens instead of 3,500-4,900.
56
+ - Regression suite: the scorer accepts a forbidden item when the result marks it with the caveat.
57
+ ### Fixed
58
+ - When several things shared a caveat, only the first was marked: the identical note next to it counted for all.
59
+
60
+ Regression runs, finished out of 7 (model minutes): 1.58 5 (214), 1.59 5 (209.5), 1.60 6 (170.6), 1.61 6 (222.1).
61
+ What is still open: a fresh prompt (when a conversation reaches its token budget) does not carry the advice to
62
+ finish, and on 1.61 the documentation task read on after one with all four items found; nothing checks that a
63
+ recipe's steps reach their end (on 1.60 cold brew stopped after step 2). Measured and not used: checking a
64
+ discovery's link to its item by shared words (most links without a shared word are right), and a 16,384-token
65
+ context, which would halve the fresh prompts but needs more memory than the default aims for.
66
+
9
67
  ## [1.57] - 2026-10-19
10
68
  Released together with the internal steps 1.54, 1.55 and 1.56, each of which was measured on the regression suite
11
69
  but not released on its own. [docs/regression-history.md](docs/regression-history.md) has every step's results,
@@ -2,3 +2,4 @@
2
2
  include CHANGELOG.md
3
3
  recursive-include tests *.py
4
4
  recursive-include tools *.py
5
+ recursive-include tests *.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localagentbrowser
3
- Version: 1.57
3
+ Version: 1.62
4
4
  Summary: An autonomous web agent driven by a local LLM (LM Studio) and Playwright. Runs entirely on your own machine.
5
5
  Author: SnowFX
6
6
  License-Expression: MIT
@@ -199,19 +199,19 @@ does not generalise; the [changelog](https://github.com/SnowFXXX/LocalAgentBrows
199
199
 
200
200
  Since 1.53, every change is measured on the same seven objectives, one of each kind above, run one after the other
201
201
  with a time limit each (`tools/regression.py`, see [Testing](#testing)). Single runs vary with the pages a search
202
- turns up, so the suite compares versions on all seven at once. 1.54 to 1.56 were internal steps measured this way
203
- and released together as 1.57; [docs/regression-history.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/docs/regression-history.md)
202
+ turns up, so the suite compares versions on all seven at once. 1.54 to 1.56 and 1.58 to 1.60 were internal steps
203
+ measured this way and released with 1.57 and 1.61; [docs/regression-history.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/docs/regression-history.md)
204
204
  has every step's results and what each one showed.
205
205
 
206
- | Task | 1.52 | 1.53 (objective checklist) | 1.57 (coverage check) |
207
- |---|---|---|---|
208
- | Factual question | Finished, 12 min | Finished, 14 min | Finished, 13 min |
209
- | List of three office suites | Time limit | Finished, 30 min; but WPS Office is not open source | Time limit: three correct open-source suites by turn 7, sent back because no words showed them to be "free" |
210
- | Comparison and recommendation | Time limit | Finished, 39 min | Time limit, after a send-back for "official documentation", which the objective does not ask for |
211
- | How-to (cold brew from 1.55; repotting before) | Time limit | Time limit | Finished, 36 min; but "how long it keeps" answered with the steeping time |
212
- | Explanation (photosynthesis) | Time limit | Finished, 13 min, but thin: no oxygen or water | Finished, 59 min: inputs, outputs and both stages, cited |
213
- | Opinion (owls) | Time limit | Finished, 38 min | Time limit: its first page covered two of the three cultures asked for |
214
- | Documentation (venv, official docs) | Finished, 15 min, from a tutorial site | Time limit (30 min) | Finished, 37 min, all from python.org; but the Windows line repeats the create command instead of the activate one |
206
+ | Task | 1.52 | 1.53 (objective checklist) | 1.57 (coverage check) | 1.61 (verified send-backs, outline pointer) |
207
+ |---|---|---|---|---|
208
+ | Factual question | Finished, 12 min | Finished, 14 min | Finished, 13 min | Finished, 17 min |
209
+ | List of three office suites | Time limit | Finished, 30 min; but WPS Office is not open source | Time limit: three correct open-source suites by turn 7, sent back because no words showed them to be "free" | Finished, 21 min: LibreOffice, WPS Office and OnlyOffice, each marked "not shown in the pages read to be free and open-source" |
210
+ | Comparison and recommendation | Time limit | Finished, 39 min | Time limit, after a send-back for "official documentation", which the objective does not ask for | Finished, 26 min, setup and administration from the part of a long page the outline pointer chose |
211
+ | How-to (cold brew from 1.55; repotting before) | Time limit | Time limit | Finished, 36 min; but "how long it keeps" answered with the steeping time | Finished, 33 min: every step, the 16-hour steep and the shelf life, cited |
212
+ | Explanation (photosynthesis) | Time limit | Finished, 13 min, but thin: no oxygen or water | Finished, 59 min: inputs, outputs and both stages, cited | Finished, 39 min |
213
+ | Opinion (owls) | Time limit | Finished, 38 min | Time limit: its first page covered two of the three cultures asked for | Finished, 42 min: four cultures, cited, with a view |
214
+ | Documentation (venv, official docs) | Finished, 15 min, from a tutorial site | Time limit (30 min) | Finished, 37 min, all from python.org; but the Windows line repeats the create command instead of the activate one | Time limit: all four items found from python.org, then it read on |
215
215
 
216
216
  ## How it works
217
217
 
@@ -237,6 +237,25 @@ flowchart LR
237
237
  C -->|FINISH| R[research_report.md]
238
238
  ```
239
239
 
240
+ ### Code layout
241
+
242
+ The code is in the `localagentbrowser` package, one file per job, each depending only on the ones above it:
243
+
244
+ | File | What it holds |
245
+ |---|---|
246
+ | `config.py` | Settings: the LM Studio connection (from environment variables) and every limit and threshold |
247
+ | `prompts.py` | Every fixed text the model reads: the system prompt, turn instructions, the checklist, coverage and final-result prompts |
248
+ | `text.py` | Small word helpers the checks share |
249
+ | `pages.py` | Reading the web: search results, page parts, the outline and its pointer, links |
250
+ | `grounding.py` | Whether a finding is really on the page shown, or already recorded |
251
+ | `checklist.py` | The objective split into a fixed checklist, and findings linked to its items |
252
+ | `coverage.py` | The coverage check before finishing, verified in code, and what is reported as not found or not proven |
253
+ | `checks.py` | Decisions refused or confirmed before they are carried out (leaving, reading on, finishing, ...) |
254
+ | `report.py` | The journal, the research log, the final result and the report file |
255
+ | `agent.py` | The loop: each turn's conversation with the model, in-turn retries, and `main()` |
256
+
257
+ `agent_browser.py` keeps `python agent_browser.py` working from a clone.
258
+
240
259
  ### Keeping a small model on track
241
260
 
242
261
  - **Rules enforced in code, not just stated in the prompt.** Repeated searches, visiting the current page,
@@ -307,8 +326,8 @@ the conversation nears the context limit. The journal uses a compact one-line-pe
307
326
  | `LMSTUDIO_API_KEY` | `lm-studio` | API key, if your server requires one |
308
327
  | `LMSTUDIO_CONTEXT_LENGTH` | `8192` | Context length the model is loaded with; the conversation budget follows it |
309
328
 
310
- Behaviour limits (part size, retry counts, check intervals and so on) are named constants at the top of
311
- `agent_browser.py`, each with a comment explaining it.
329
+ Behaviour limits (part size, retry counts, check intervals and so on) are named constants in
330
+ `localagentbrowser/config.py`, each with a comment explaining it.
312
331
 
313
332
  ## Performance
314
333
 
@@ -323,9 +342,9 @@ Measured on an Intel i5-9500 (6 cores, no GPU) with Qwen2.5-7B-Instruct Q4_K_M a
323
342
  | Coverage check before finishing (all checklist items) | about 1–3 min |
324
343
  | Writing the final result (once, at the end) | 50–190 s, depending on how much was found |
325
344
 
326
- Whole runs vary with the pages a search turns up. In the regression runs since 1.53, a factual question took 13 to
327
- 19 minutes of model time; the list, comparison, how-to, opinion and documentation tasks 21 to 44 when they finished;
328
- and the explanation 13 to 59. A GPU or a smaller model will be much faster.
345
+ Whole runs vary with the pages a search turns up. In the regression runs since 1.53, a factual question took 9 to
346
+ 19 minutes of model time; the list, comparison, how-to, opinion and documentation tasks 17 to 44 when they finished;
347
+ and the explanation 13 to 59. A whole suite of seven tasks took 171 to 272 minutes. A GPU or a smaller model will be much faster.
329
348
 
330
349
  ## FAQ
331
350
 
@@ -363,15 +382,17 @@ turn that brings in a new page takes a few minutes. See [Performance](#performan
363
382
  - **Judging whether a finding covers an item is the weakest area.** The model's verdict is unreliable both ways:
364
383
  on 1.53 the explanation finished from one overview paragraph without oxygen or water, and in the regression runs
365
384
  since 1.54 about half of the coverage check's send-backs were for gaps that were not real ("missing official
366
- documentation" on a comparison that did not ask for it, "H2O, O2" already recorded). The code now verifies what
367
- it can (an item nothing answers, a count, word-for-word proof of a condition), but each wrong send-back still
368
- costs a finish on this hardware, since a send-back costs 8–10 minutes.
385
+ documentation" on a comparison that did not ask for it, "H2O, O2" already recorded). Since 1.58 the agent is sent
386
+ back only for what the code verifies (an item nothing answers, fewer things than asked for); the model's other
387
+ verdicts only shape the final result, so a thin answer can still pass (on 1.61 the comparison's "many
388
+ simultaneous users" part is short).
369
389
  - **Conditions in the objective.** A small model tends to drop conditions such as "open source" or "using the
370
390
  official documentation": a list of open-source office suites once included FreeOffice (free but not open
371
391
  source), and a task that asked for the official Python documentation used a tutorial site. The objective
372
392
  checklist keeps the conditions in view (the documentation task uses python.org since 1.55), and a thing not
373
- shown in the findings to meet a condition is left out of the result and listed after it. The check is strict:
374
- on 1.57 it sent back three correct open-source suites because no words showed them to be "free". Check the
393
+ shown in the findings to meet a condition is marked where it is named ("not shown in the pages read to be free
394
+ and open-source"). The mark says what the pages read did not show, not that the thing fails the condition: on
395
+ 1.61 it marked LibreOffice and OnlyOffice, which are open source, as well as WPS Office, which is not. Check the
375
396
  result against any conditions you set.
376
397
  - **A small model's judgement is the ceiling.** It sometimes drifts to loosely related pages, prefers
377
398
  secondary sources or stays with one source too long, and results vary with the first pages a search turns
@@ -402,8 +423,10 @@ turn that brings in a new page takes a few minutes. See [Performance](#performan
402
423
  - [x] Keep a fixed checklist of the objective's parts instead of re-splitting it at every check (1.53)
403
424
  - [ ] Check that a finding really covers its checklist item, including conditions like "open source" (partly, since
404
425
  1.57: a coverage check before finishing, with what the code can verify)
405
- - [ ] Send the agent back only for gaps the code verifies, and let the model's other verdicts only shape the final
406
- result (the next step after 1.57)
426
+ - [x] Send the agent back only for gaps the code verifies, and let the model's other verdicts only shape the final
427
+ result (1.58, released in 1.61)
428
+ - [x] Point the agent to the part of a long page whose outline names an item it still needs (1.61)
429
+ - [ ] Keep the advice to finish when a conversation starts over from a fresh prompt (the next step after 1.61)
407
430
  - [ ] Rewind dead ends: save the conversation before an expensive step such as reading a long page, and if it
408
431
  leads nowhere, return to that point with a short note instead of carrying the unused page text in every later
409
432
  prompt (LM Studio reuses its cache up to the saved point)
@@ -424,6 +447,12 @@ python -m pytest
424
447
  python -m ruff check .
425
448
  ```
426
449
 
450
+ `tests/test_golden_prompts.py` replays five scripted runs and compares every message sent to the model, and the
451
+ journal and report, with a recorded copy in `tests/golden/prompts.json`. A change meant to leave the agent's
452
+ behaviour alone must keep it passing unchanged; a deliberate change to what the model sees is recorded again with
453
+ `GOLDEN_UPDATE=1 python -m pytest tests/test_golden_prompts.py`, and the diff of the recorded copy reviewed with
454
+ the rest of the change.
455
+
427
456
  To try the real agent with a fixed objective and a time limit, logging the time and tokens of every model
428
457
  call:
429
458
 
@@ -456,8 +485,8 @@ the [Code of Conduct](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/CO
456
485
  ## Project history
457
486
 
458
487
  Every released version is a tagged commit, and [CHANGELOG.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/CHANGELOG.md) describes what changed in each one and
459
- why, with the measurements behind the decisions. Versions 1.54 to 1.56 were internal steps, each measured on the
460
- regression suite and released together as 1.57; their results are in
488
+ why, with the measurements behind the decisions. Versions 1.54 to 1.56 and 1.58 to 1.60 were internal steps, each
489
+ measured on the regression suite and released with 1.57 and 1.61; their results are in
461
490
  [docs/regression-history.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/docs/regression-history.md).
462
491
 
463
492
  ## Acknowledgements
@@ -167,19 +167,19 @@ does not generalise; the [changelog](https://github.com/SnowFXXX/LocalAgentBrows
167
167
 
168
168
  Since 1.53, every change is measured on the same seven objectives, one of each kind above, run one after the other
169
169
  with a time limit each (`tools/regression.py`, see [Testing](#testing)). Single runs vary with the pages a search
170
- turns up, so the suite compares versions on all seven at once. 1.54 to 1.56 were internal steps measured this way
171
- and released together as 1.57; [docs/regression-history.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/docs/regression-history.md)
170
+ turns up, so the suite compares versions on all seven at once. 1.54 to 1.56 and 1.58 to 1.60 were internal steps
171
+ measured this way and released with 1.57 and 1.61; [docs/regression-history.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/docs/regression-history.md)
172
172
  has every step's results and what each one showed.
173
173
 
174
- | Task | 1.52 | 1.53 (objective checklist) | 1.57 (coverage check) |
175
- |---|---|---|---|
176
- | Factual question | Finished, 12 min | Finished, 14 min | Finished, 13 min |
177
- | List of three office suites | Time limit | Finished, 30 min; but WPS Office is not open source | Time limit: three correct open-source suites by turn 7, sent back because no words showed them to be "free" |
178
- | Comparison and recommendation | Time limit | Finished, 39 min | Time limit, after a send-back for "official documentation", which the objective does not ask for |
179
- | How-to (cold brew from 1.55; repotting before) | Time limit | Time limit | Finished, 36 min; but "how long it keeps" answered with the steeping time |
180
- | Explanation (photosynthesis) | Time limit | Finished, 13 min, but thin: no oxygen or water | Finished, 59 min: inputs, outputs and both stages, cited |
181
- | Opinion (owls) | Time limit | Finished, 38 min | Time limit: its first page covered two of the three cultures asked for |
182
- | Documentation (venv, official docs) | Finished, 15 min, from a tutorial site | Time limit (30 min) | Finished, 37 min, all from python.org; but the Windows line repeats the create command instead of the activate one |
174
+ | Task | 1.52 | 1.53 (objective checklist) | 1.57 (coverage check) | 1.61 (verified send-backs, outline pointer) |
175
+ |---|---|---|---|---|
176
+ | Factual question | Finished, 12 min | Finished, 14 min | Finished, 13 min | Finished, 17 min |
177
+ | List of three office suites | Time limit | Finished, 30 min; but WPS Office is not open source | Time limit: three correct open-source suites by turn 7, sent back because no words showed them to be "free" | Finished, 21 min: LibreOffice, WPS Office and OnlyOffice, each marked "not shown in the pages read to be free and open-source" |
178
+ | Comparison and recommendation | Time limit | Finished, 39 min | Time limit, after a send-back for "official documentation", which the objective does not ask for | Finished, 26 min, setup and administration from the part of a long page the outline pointer chose |
179
+ | How-to (cold brew from 1.55; repotting before) | Time limit | Time limit | Finished, 36 min; but "how long it keeps" answered with the steeping time | Finished, 33 min: every step, the 16-hour steep and the shelf life, cited |
180
+ | Explanation (photosynthesis) | Time limit | Finished, 13 min, but thin: no oxygen or water | Finished, 59 min: inputs, outputs and both stages, cited | Finished, 39 min |
181
+ | Opinion (owls) | Time limit | Finished, 38 min | Time limit: its first page covered two of the three cultures asked for | Finished, 42 min: four cultures, cited, with a view |
182
+ | Documentation (venv, official docs) | Finished, 15 min, from a tutorial site | Time limit (30 min) | Finished, 37 min, all from python.org; but the Windows line repeats the create command instead of the activate one | Time limit: all four items found from python.org, then it read on |
183
183
 
184
184
  ## How it works
185
185
 
@@ -205,6 +205,25 @@ flowchart LR
205
205
  C -->|FINISH| R[research_report.md]
206
206
  ```
207
207
 
208
+ ### Code layout
209
+
210
+ The code is in the `localagentbrowser` package, one file per job, each depending only on the ones above it:
211
+
212
+ | File | What it holds |
213
+ |---|---|
214
+ | `config.py` | Settings: the LM Studio connection (from environment variables) and every limit and threshold |
215
+ | `prompts.py` | Every fixed text the model reads: the system prompt, turn instructions, the checklist, coverage and final-result prompts |
216
+ | `text.py` | Small word helpers the checks share |
217
+ | `pages.py` | Reading the web: search results, page parts, the outline and its pointer, links |
218
+ | `grounding.py` | Whether a finding is really on the page shown, or already recorded |
219
+ | `checklist.py` | The objective split into a fixed checklist, and findings linked to its items |
220
+ | `coverage.py` | The coverage check before finishing, verified in code, and what is reported as not found or not proven |
221
+ | `checks.py` | Decisions refused or confirmed before they are carried out (leaving, reading on, finishing, ...) |
222
+ | `report.py` | The journal, the research log, the final result and the report file |
223
+ | `agent.py` | The loop: each turn's conversation with the model, in-turn retries, and `main()` |
224
+
225
+ `agent_browser.py` keeps `python agent_browser.py` working from a clone.
226
+
208
227
  ### Keeping a small model on track
209
228
 
210
229
  - **Rules enforced in code, not just stated in the prompt.** Repeated searches, visiting the current page,
@@ -275,8 +294,8 @@ the conversation nears the context limit. The journal uses a compact one-line-pe
275
294
  | `LMSTUDIO_API_KEY` | `lm-studio` | API key, if your server requires one |
276
295
  | `LMSTUDIO_CONTEXT_LENGTH` | `8192` | Context length the model is loaded with; the conversation budget follows it |
277
296
 
278
- Behaviour limits (part size, retry counts, check intervals and so on) are named constants at the top of
279
- `agent_browser.py`, each with a comment explaining it.
297
+ Behaviour limits (part size, retry counts, check intervals and so on) are named constants in
298
+ `localagentbrowser/config.py`, each with a comment explaining it.
280
299
 
281
300
  ## Performance
282
301
 
@@ -291,9 +310,9 @@ Measured on an Intel i5-9500 (6 cores, no GPU) with Qwen2.5-7B-Instruct Q4_K_M a
291
310
  | Coverage check before finishing (all checklist items) | about 1–3 min |
292
311
  | Writing the final result (once, at the end) | 50–190 s, depending on how much was found |
293
312
 
294
- Whole runs vary with the pages a search turns up. In the regression runs since 1.53, a factual question took 13 to
295
- 19 minutes of model time; the list, comparison, how-to, opinion and documentation tasks 21 to 44 when they finished;
296
- and the explanation 13 to 59. A GPU or a smaller model will be much faster.
313
+ Whole runs vary with the pages a search turns up. In the regression runs since 1.53, a factual question took 9 to
314
+ 19 minutes of model time; the list, comparison, how-to, opinion and documentation tasks 17 to 44 when they finished;
315
+ and the explanation 13 to 59. A whole suite of seven tasks took 171 to 272 minutes. A GPU or a smaller model will be much faster.
297
316
 
298
317
  ## FAQ
299
318
 
@@ -331,15 +350,17 @@ turn that brings in a new page takes a few minutes. See [Performance](#performan
331
350
  - **Judging whether a finding covers an item is the weakest area.** The model's verdict is unreliable both ways:
332
351
  on 1.53 the explanation finished from one overview paragraph without oxygen or water, and in the regression runs
333
352
  since 1.54 about half of the coverage check's send-backs were for gaps that were not real ("missing official
334
- documentation" on a comparison that did not ask for it, "H2O, O2" already recorded). The code now verifies what
335
- it can (an item nothing answers, a count, word-for-word proof of a condition), but each wrong send-back still
336
- costs a finish on this hardware, since a send-back costs 8–10 minutes.
353
+ documentation" on a comparison that did not ask for it, "H2O, O2" already recorded). Since 1.58 the agent is sent
354
+ back only for what the code verifies (an item nothing answers, fewer things than asked for); the model's other
355
+ verdicts only shape the final result, so a thin answer can still pass (on 1.61 the comparison's "many
356
+ simultaneous users" part is short).
337
357
  - **Conditions in the objective.** A small model tends to drop conditions such as "open source" or "using the
338
358
  official documentation": a list of open-source office suites once included FreeOffice (free but not open
339
359
  source), and a task that asked for the official Python documentation used a tutorial site. The objective
340
360
  checklist keeps the conditions in view (the documentation task uses python.org since 1.55), and a thing not
341
- shown in the findings to meet a condition is left out of the result and listed after it. The check is strict:
342
- on 1.57 it sent back three correct open-source suites because no words showed them to be "free". Check the
361
+ shown in the findings to meet a condition is marked where it is named ("not shown in the pages read to be free
362
+ and open-source"). The mark says what the pages read did not show, not that the thing fails the condition: on
363
+ 1.61 it marked LibreOffice and OnlyOffice, which are open source, as well as WPS Office, which is not. Check the
343
364
  result against any conditions you set.
344
365
  - **A small model's judgement is the ceiling.** It sometimes drifts to loosely related pages, prefers
345
366
  secondary sources or stays with one source too long, and results vary with the first pages a search turns
@@ -370,8 +391,10 @@ turn that brings in a new page takes a few minutes. See [Performance](#performan
370
391
  - [x] Keep a fixed checklist of the objective's parts instead of re-splitting it at every check (1.53)
371
392
  - [ ] Check that a finding really covers its checklist item, including conditions like "open source" (partly, since
372
393
  1.57: a coverage check before finishing, with what the code can verify)
373
- - [ ] Send the agent back only for gaps the code verifies, and let the model's other verdicts only shape the final
374
- result (the next step after 1.57)
394
+ - [x] Send the agent back only for gaps the code verifies, and let the model's other verdicts only shape the final
395
+ result (1.58, released in 1.61)
396
+ - [x] Point the agent to the part of a long page whose outline names an item it still needs (1.61)
397
+ - [ ] Keep the advice to finish when a conversation starts over from a fresh prompt (the next step after 1.61)
375
398
  - [ ] Rewind dead ends: save the conversation before an expensive step such as reading a long page, and if it
376
399
  leads nowhere, return to that point with a short note instead of carrying the unused page text in every later
377
400
  prompt (LM Studio reuses its cache up to the saved point)
@@ -392,6 +415,12 @@ python -m pytest
392
415
  python -m ruff check .
393
416
  ```
394
417
 
418
+ `tests/test_golden_prompts.py` replays five scripted runs and compares every message sent to the model, and the
419
+ journal and report, with a recorded copy in `tests/golden/prompts.json`. A change meant to leave the agent's
420
+ behaviour alone must keep it passing unchanged; a deliberate change to what the model sees is recorded again with
421
+ `GOLDEN_UPDATE=1 python -m pytest tests/test_golden_prompts.py`, and the diff of the recorded copy reviewed with
422
+ the rest of the change.
423
+
395
424
  To try the real agent with a fixed objective and a time limit, logging the time and tokens of every model
396
425
  call:
397
426
 
@@ -424,8 +453,8 @@ the [Code of Conduct](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/CO
424
453
  ## Project history
425
454
 
426
455
  Every released version is a tagged commit, and [CHANGELOG.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/CHANGELOG.md) describes what changed in each one and
427
- why, with the measurements behind the decisions. Versions 1.54 to 1.56 were internal steps, each measured on the
428
- regression suite and released together as 1.57; their results are in
456
+ why, with the measurements behind the decisions. Versions 1.54 to 1.56 and 1.58 to 1.60 were internal steps, each
457
+ measured on the regression suite and released with 1.57 and 1.61; their results are in
429
458
  [docs/regression-history.md](https://github.com/SnowFXXX/LocalAgentBrowser/blob/main/docs/regression-history.md).
430
459
 
431
460
  ## Acknowledgements
@@ -0,0 +1,23 @@
1
+ """LocalAgentBrowser: an autonomous web agent driven by a local language model.
2
+
3
+ Run: python agent_browser.py (or `localagentbrowser` once installed; it asks for the objective)
4
+
5
+ The code lives in the localagentbrowser package (see its __init__.py for how it is organized). This file keeps
6
+ `python agent_browser.py` working from a clone, and `import agent_browser` working for the tests and tools: it
7
+ gives access to every name in the package. To replace a part of the agent in a test, patch the module that
8
+ uses it (for example localagentbrowser.agent.AsyncOpenAI), not this file.
9
+ """
10
+ from localagentbrowser.config import * # noqa: F403
11
+ from localagentbrowser.prompts import * # noqa: F403
12
+ from localagentbrowser.text import * # noqa: F403
13
+ from localagentbrowser.pages import * # noqa: F403
14
+ from localagentbrowser.grounding import * # noqa: F403
15
+ from localagentbrowser.checklist import * # noqa: F403
16
+ from localagentbrowser.coverage import * # noqa: F403
17
+ from localagentbrowser.checks import * # noqa: F403
18
+ from localagentbrowser.report import * # noqa: F403
19
+ from localagentbrowser.agent import * # noqa: F403
20
+ from localagentbrowser.agent import main, run # noqa: F401
21
+
22
+ if __name__ == "__main__":
23
+ run()
@@ -0,0 +1,26 @@
1
+ """LocalAgentBrowser: an autonomous web agent driven by a local language model.
2
+
3
+ A model served by LM Studio decides, one JSON action at a time, whether to SEARCH, NAVIGATE, READ_MORE,
4
+ DISCOVER or FINISH; Playwright carries the actions out in a visible Chromium window. Everything the
5
+ agent does and finds is written to research_log.txt.
6
+
7
+ Run: python agent_browser.py (or `localagentbrowser` once installed; it asks for the objective)
8
+
9
+ Settings (environment variables):
10
+ LMSTUDIO_BASE_URL OpenAI-compatible server address (default http://localhost:1234/v1)
11
+ LMSTUDIO_MODEL model identifier (default qwen2.5-7b-instruct)
12
+ LMSTUDIO_API_KEY API key, if the server needs one (default lm-studio)
13
+ LMSTUDIO_CONTEXT_LENGTH context length the model is loaded with (default 8192)
14
+
15
+ The package, one file per job; each imports only from the ones listed before it:
16
+ config settings and every limit and threshold
17
+ prompts every fixed text the model reads
18
+ text small word helpers the checks share
19
+ pages search results, page parts, the outline and its pointer, links
20
+ grounding whether a finding is really on the page shown, or already recorded
21
+ checklist the objective split into a fixed checklist; findings linked to its items
22
+ coverage the coverage check before finishing, verified in code
23
+ checks decisions refused or confirmed before they are carried out
24
+ report the journal, research log, final result and report file
25
+ agent the loop: each turn's conversation with the model, and main()
26
+ """