-
Notifications
You must be signed in to change notification settings - Fork 367
Web Skill Factory: evolving reusable, verified, code-native skills for web agents #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
DEM1TASSE
wants to merge
51
commits into
microsoft:main
Choose a base branch
from
DEM1TASSE:skill-library
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
4ae9ab8
skills: add webwright.skills memory/skill-library module + skill_use …
DEM1TASSE 91a2090
skills: prompt hint helper + skill_mode overlay; env-based model for …
DEM1TASSE a96336b
skills: README for the module + env-based model for bare CLI
DEM1TASSE 82fe0ba
docs+tests: README skill-library section + skills unit tests
DEM1TASSE 05aab3a
skills: translate all comments/docstrings to English
DEM1TASSE bb0d0cd
skills: drop dead code in update (grow path superseded by evolve)
DEM1TASSE ba4fa2a
skills: fix refine truncation + timeout + fence stripping (found in e…
DEM1TASSE 2784fc6
skills README: add end-to-end How-to-use (manifest schema, params, so…
DEM1TASSE c293a48
skills README: batch pipeline example (tasks.json -> solve loop -> ga…
DEM1TASSE 7deab76
skills README: manifest field-by-field table; Results summary with We…
DEM1TASSE f7b0779
skills: harden pipeline entry points (review findings)
DEM1TASSE d0c6d84
skills: manifest 'admit' must be a JSON boolean (hand-written "false"…
DEM1TASSE 6060bd5
skills: fix cleanroom-repro findings (silent empty-library skip, rela…
DEM1TASSE 4682a47
skills: add examples/ — a real evolve-produced skill, measured saving…
DEM1TASSE 1234788
skills README: narrative intro (programs not notes, gate, aggregation…
DEM1TASSE 3612e89
skills: friendly entry — 'learn' turns a folder of runs into skills (…
DEM1TASSE b656e6c
skills: fix learn-interface test findings (silent-reuse-off, tracebac…
DEM1TASSE 5cac233
skills README: env exports at the top of Quickstart (step-1-only read…
DEM1TASSE 64a4feb
skills: release-gap fixes — gate honesty, aggregation showcase, regre…
DEM1TASSE ddca588
ci: run skills unit tests + wrapper usage check on module changes
DEM1TASSE 06d72b3
evals: make the WebArena numbers reproducible (evals/webarena/)
DEM1TASSE 6513d87
skills: address Copilot review findings
DEM1TASSE 8ea59be
skills: address review — complete Quickstart, drop skill_mode.yaml, c…
DEM1TASSE 7acbdd4
skills: Quickstart on Google Flights — Webwright's own example task
DEM1TASSE 223597a
skills: record the three-way consistency check on the held-out route
DEM1TASSE 9286493
skills: measured cost table in Quickstart; single flights example
DEM1TASSE bb67e3e
skills: trim Quickstart cost table to steps + wall time
DEM1TASSE b9b95e2
skills: step savings scale with unfamiliarity/variance, not zero
DEM1TASSE b32cc76
skills: self_verify also honors the agent's own final report (free si…
DEM1TASSE 3dfdfd0
skills: end-to-end regression for the status-aware self_verify gate
DEM1TASSE 4a6036b
skills: one-command quickstart.sh — every parameter pre-filled
DEM1TASSE c8b27c5
skills: quickstart.sh usage path robust to caller cwd
DEM1TASSE dc8c870
evals: collapse 100 per-task result files into one results.json
DEM1TASSE f729099
evals: drop the WebArena repro package from the PR (kept locally)
DEM1TASSE 7afb6c0
skills: skills never write artifacts next to __file__; gateway solve-…
DEM1TASSE c34eb9b
skills: docs run standalone skills from scratch dirs, not repo dirs
DEM1TASSE f8d047d
skills: pipeline diagram shows evolve's code input and template bucke…
DEM1TASSE 9786424
skills: replay-verify distilled skills before they enter the library
DEM1TASSE 0c29b9f
skills: replay comparator normalizes scalars; manifest carries creden…
DEM1TASSE 693d816
skills: rejected skills leave their runs un-learned (retry possible)
DEM1TASSE 0b74074
skills: standalone-reproduces-its-answers is now the default bar
DEM1TASSE bcd8210
skills: two skill grades + regression-checked incremental refine
DEM1TASSE c3331c4
rename: webwright.skills -> webwright.skill_lab (Webwright Skill Lab)
DEM1TASSE 9859176
rename: final name Web Skill Factory (module webwright.skill_factory)
DEM1TASSE aaf9f99
examples: single checked-in library, diagram moved to assets/
DEM1TASSE aefbd53
README: tight overview, details pushed down, demo shipped in assets
DEM1TASSE fb9aa04
Revise README for skill factory module
DEM1TASSE 325994a
README: landing page in the parent repo's register; reference into docs/
DEM1TASSE cbd7db4
docs: three references; full eval table and design move into the README
DEM1TASSE d12cee0
README: cost table to quickstart doc, richer Design; diagram gains re…
DEM1TASSE 36c5780
quickstart: close the gateway traps from the external repro
DEM1TASSE File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| name: skills-tests | ||
| on: | ||
| push: | ||
| paths: ["src/webwright/skill_factory/**", "src/webwright/tools/skill_use.py", "tests/skill_factory/**"] | ||
| pull_request: | ||
| paths: ["src/webwright/skill_factory/**", "src/webwright/tools/skill_use.py", "tests/skill_factory/**"] | ||
| jobs: | ||
| unit: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-python@v5 | ||
| with: { python-version: "3.12" } | ||
| - run: pip install httpx pyyaml jinja2 pydantic | ||
| - name: skills unit tests (LLM-free) | ||
| run: | | ||
| set -e | ||
| for t in tests/skill_factory/test_*.py; do | ||
| echo "== $t"; PYTHONPATH=src python "$t" | ||
| done | ||
| - name: wrapper usage check (F6) | ||
| run: | | ||
| set +e | ||
| bash src/webwright/skill_factory/examples/solve_with_library.sh > /dev/null 2>&1 | ||
| [ $? -eq 1 ] && echo "usage-exit OK" || { echo "wrapper must exit 1 on missing args"; exit 1; } | ||
| bash -n src/webwright/skill_factory/examples/quickstart.sh || exit 1 | ||
| bash src/webwright/skill_factory/examples/quickstart.sh badmode > /dev/null 2>&1 | ||
| [ $? -eq 1 ] && echo "quickstart usage-exit OK" || { echo "quickstart must exit 1 on bad mode"; exit 1; } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| # Web Skill Factory | ||
|
|
||
| **Most agent skills are context the model refers to. Ours are programs.** | ||
|
|
||
| Each solved task becomes runnable, parameterized code — verify it, run it without the | ||
| model, and import it into the next task instead of re-exploring. | ||
|
|
||
| Module: `webwright.skill_factory`, built on Webwright. | ||
|
|
||
| ## 🎥 Demo | ||
|
|
||
| https://github.com/user-attachments/assets/d15b1f83-2c8d-4f2d-bbc5-be365c0bcf4e | ||
|
|
||
| ## ✨ Why | ||
|
|
||
| - 🧩 **Import, don't just refer** — skills are executable code; a learned skill re-runs | ||
| standalone in ~30 s with **no model in the loop** | ||
| - 🌱 **Self-evolving** — each batch of solves is gated, grouped by template, distilled; | ||
| wrong answers never enter, working skills never break | ||
| - ✅ **Replay-verified** — a skill must reproduce its own training answers standalone | ||
| before it may land | ||
| - 💸 **Cheap to adopt** — one tool + one CLI, zero agent-loop changes | ||
|
|
||
| ## 🗺️ How it works | ||
|
|
||
|  | ||
|
|
||
| ``` | ||
| solve → gate → group by template → distill → replay-verify → library → next solve reuses | ||
| ``` | ||
|
|
||
| At solve time the agent asks the library once and gets `use` / `adapt` / `skip` — | ||
| reuse never blocks solving. | ||
|
|
||
| ## 🚀 Quick Start | ||
|
|
||
| ```bash | ||
| cd src/webwright/skill_factory/examples | ||
| ./quickstart.sh # a learned skill drives a live site — no model, no API key needed | ||
| ``` | ||
|
|
||
| <details> | ||
| <summary><b>More modes</b> — reuse with the agent, or rebuild the library yourself</summary> | ||
|
|
||
| <br> | ||
|
|
||
| ```bash | ||
| export OPENAI_API_KEY=... | ||
| ./quickstart.sh ask # ask the library about a task it has never seen | ||
| ./quickstart.sh solve # the agent REUSES the checked-in skill on a new route | ||
| ./quickstart.sh full # the whole loop: 3 solves -> learn -> reuse (~30 min) | ||
| ``` | ||
|
|
||
| On a custom OpenAI-compatible gateway, also `export OPENAI_ENDPOINT=... OPENAI_MODEL=...` | ||
| (for learn / skill_use; the endpoint is the FULL `.../responses` URL, not a base path) and | ||
| `export MODEL_CFG=...` pointing at a copy of `examples/model_gateway.example.yaml` (for the | ||
| agent — it reads a yaml, not these env vars). | ||
|
|
||
| </details> | ||
|
|
||
| Full tutorial — the loop spelled out, gateway setup, running skills without the agent: | ||
| **[docs/quickstart.md](docs/quickstart.md)** | ||
|
|
||
| ## 📊 Results | ||
|
|
||
| **Setting** — WebArena, 10 retrieve-type task templates across 3 self-hosted sites | ||
| (shopping-admin, gitlab, map). Per template: 3 train solves build the library | ||
| (gold-gated), 2 held-out instances measure reuse; every held-out task is solved both | ||
| WITH the library and from scratch. Same model, same budget, 100 solves total. | ||
|
|
||
| | | WITH library | from scratch | Δ | | ||
| |-------------------------|--------------|--------------|---------| | ||
| | held-out accuracy (20) | **70%** | 55% | **+15 pp** | | ||
| | held-out avg steps | **14.7** | 17.1 | −2.4 | | ||
| | train accuracy (30) | **86.7%** | 76.7% | +10 pp | | ||
| | train avg steps | **13.7** | 15.9 | −2.2 | | ||
|
|
||
| - **4 held-out tasks rescued** (wrong → correct); net reuse-wins vs regressions **7 : 1**; | ||
| biggest win **33 → 10 steps** | ||
| - retrieval stayed reliable as the library grew: all 20 held-out solves picked the right | ||
| skill, including two near-duplicate templates | ||
| - mixed-template batches evolve safely: adds, refines and keeps with zero cross-contamination | ||
|
|
||
| ## 🧠 Design | ||
|
|
||
| **Actions are already code.** Webwright solves by writing code — every solve leaves a | ||
| working script behind, so skills are a byproduct, not an instrumentation layer. It | ||
| complements `crafted_cli`: craft parameterizes one script by *anticipating* what might | ||
| vary; the factory parameterizes across solves from the differences *actually observed*. | ||
|
|
||
| **One solve isn't a skill yet.** A single script is correct but narrow. Aggregating | ||
| verified solves of the same template turns observed differences into parameters and | ||
| recurring patterns into primitives — different runs' strategies become fallbacks, and | ||
| what lands is the best algorithm the solves discovered. | ||
|
|
||
| **Parameters are evidence, primitives are the product.** Parameters aren't guessed up | ||
| front — they are the differences actually observed between solves. The expensive core is | ||
| factored into named primitives (`login()`, `open_grid()`, `extract_rows()`) with a thin | ||
| task layer on top, so future tasks can reuse and compose the pieces even when the final | ||
| step differs. | ||
|
|
||
| **Nothing lands unproven.** The admission gate checks the *inputs*, but distillation | ||
| itself can introduce bugs — and an agent reading a broken skill as source will quietly | ||
| work around them, so agent-in-loop numbers alone can't certify a library. The proof is | ||
| model-free execution: a skill must replay its own training taskspecs standalone and | ||
| reproduce the answers before it lands, and every skill carries its grade — | ||
| `executable` (proved) or `reference` (a prior the agent may still read). | ||
|
|
||
| **Growth never breaks what works.** New templates add skills, new solves refine existing | ||
| ones in place (regression-replayed against their stored training examples), untouched | ||
| skills stay byte-identical. | ||
|
|
||
| ## 🔌 Plugs into Webwright | ||
|
|
||
| Two touch points, no agent-loop changes: | ||
|
|
||
| ```bash | ||
| python -m webwright.tools.skill_use --task "<task>" --library ./library # reuse at solve time | ||
| python -m webwright.skill_factory learn outputs/ --library ./library # grow it afterwards | ||
| ``` | ||
|
|
||
| ## 📚 Documentation | ||
|
|
||
| | doc | what's in it | | ||
| |---|---| | ||
| | [docs/quickstart.md](docs/quickstart.md) | the complete tutorial: the flights loop, gateway knobs, standalone usage, measured costs | | ||
| | [docs/manual.md](docs/manual.md) | manual mode: manifests field by field, gold gates, the batch pipeline | | ||
| | [docs/reference.md](docs/reference.md) | verification & grades, every flag and env var, component map, backend | | ||
| | [examples/README.md](examples/README.md) | the checked-in skill and the example inputs | | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DEM1TASSE It is better to add the complete example in the quick start session.
It needs to additionally include how to use the skill library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 8ea59be — the Quickstart is now the complete loop on a copy-pasteable example (public GitHub): solve 3 instances ->
learn-> an unseen instance reuses the skill (with the expectedskill_decision.jsonshown), plus how to use the library without the agent (queryingskill_usedirectly, and running the learned skill standalone with no model — verified pandas-dev/pandas -> v3.0.4). The same loop's output is checked in atexamples/learned_library/.