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.
- {localagentbrowser-1.57 → localagentbrowser-1.62}/CHANGELOG.md +60 -2
- {localagentbrowser-1.57 → localagentbrowser-1.62}/MANIFEST.in +1 -0
- {localagentbrowser-1.57/localagentbrowser.egg-info → localagentbrowser-1.62}/PKG-INFO +55 -26
- {localagentbrowser-1.57 → localagentbrowser-1.62}/README.md +54 -25
- localagentbrowser-1.62/agent_browser.py +23 -0
- localagentbrowser-1.62/localagentbrowser/__init__.py +26 -0
- localagentbrowser-1.62/localagentbrowser/agent.py +406 -0
- localagentbrowser-1.62/localagentbrowser/checklist.py +93 -0
- localagentbrowser-1.62/localagentbrowser/checks.py +248 -0
- localagentbrowser-1.62/localagentbrowser/config.py +96 -0
- localagentbrowser-1.62/localagentbrowser/coverage.py +175 -0
- localagentbrowser-1.62/localagentbrowser/grounding.py +121 -0
- localagentbrowser-1.62/localagentbrowser/pages.py +396 -0
- localagentbrowser-1.62/localagentbrowser/prompts.py +104 -0
- localagentbrowser-1.62/localagentbrowser/report.py +208 -0
- localagentbrowser-1.62/localagentbrowser/text.py +54 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62/localagentbrowser.egg-info}/PKG-INFO +55 -26
- {localagentbrowser-1.57 → localagentbrowser-1.62}/localagentbrowser.egg-info/SOURCES.txt +13 -0
- localagentbrowser-1.62/localagentbrowser.egg-info/entry_points.txt +2 -0
- localagentbrowser-1.62/localagentbrowser.egg-info/top_level.txt +2 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/pyproject.toml +3 -2
- localagentbrowser-1.62/tests/golden/prompts.json +2288 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_checklist.py +103 -8
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_decisions.py +3 -2
- localagentbrowser-1.62/tests/test_golden_prompts.py +133 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_journal.py +7 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_main_loop.py +6 -5
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_model_turns.py +2 -1
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_page_text.py +16 -2
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/test_regression.py +6 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tools/live_test.py +3 -2
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tools/regression.py +4 -1
- localagentbrowser-1.57/agent_browser.py +0 -1658
- localagentbrowser-1.57/localagentbrowser.egg-info/entry_points.txt +0 -2
- localagentbrowser-1.57/localagentbrowser.egg-info/top_level.txt +0 -1
- {localagentbrowser-1.57 → localagentbrowser-1.62}/LICENSE +0 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/localagentbrowser.egg-info/dependency_links.txt +0 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/localagentbrowser.egg-info/requires.txt +0 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/setup.cfg +0 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/conftest.py +0 -0
- {localagentbrowser-1.57 → localagentbrowser-1.62}/tests/fakes.py +0 -0
- {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
|
|
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,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: localagentbrowser
|
|
3
|
-
Version: 1.
|
|
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
|
|
203
|
-
and released
|
|
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
|
|
311
|
-
`
|
|
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
|
|
327
|
-
19 minutes of model time; the list, comparison, how-to, opinion and documentation tasks
|
|
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).
|
|
367
|
-
|
|
368
|
-
|
|
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
|
|
374
|
-
|
|
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
|
-
- [
|
|
406
|
-
result (
|
|
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
|
|
460
|
-
regression suite and released
|
|
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
|
|
171
|
-
and released
|
|
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
|
|
279
|
-
`
|
|
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
|
|
295
|
-
19 minutes of model time; the list, comparison, how-to, opinion and documentation tasks
|
|
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).
|
|
335
|
-
|
|
336
|
-
|
|
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
|
|
342
|
-
|
|
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
|
-
- [
|
|
374
|
-
result (
|
|
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
|
|
428
|
-
regression suite and released
|
|
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
|
+
"""
|