poltertab 1.6.0-beta.1 → 1.6.0-beta.2

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.
@@ -32,6 +32,28 @@ const SINK = {
32
32
  // Self-healing: browser_click/browser_fill return the resolved element's
33
33
  // fingerprint. Pass it back on a later call and, if the selector has drifted
34
34
  // (a renamed id/class), the element is relocated by structural similarity.
35
+ // Learned recipes: a spec that produced clean rows is stored per host and page
36
+ // shape, so a later extract on the same shape can omit it entirely. Shared by
37
+ // browser_extract and browser_extract_all because the stored spec is the same
38
+ // spec — a recipe learned by one is replayed by the other.
39
+ const RECIPE = {
40
+ recipe: {
41
+ type: "string",
42
+ description:
43
+ "Name of a learned recipe to replay. Only needed when more than one has been learned for this page shape — with exactly one, omitting `record`/`fields` uses it. browser_navigate lists what exists in `recipes_available`, and browser_get_site_memory has the detail.",
44
+ },
45
+ variant: {
46
+ type: "string",
47
+ description:
48
+ "Which slice of the recipe to replay (a filter combination it was learned under). Only needed when the recipe has more than one. Variant names are derived from the steps that preceded the extract, so browser_get_site_memory shows which slice each one is.",
49
+ },
50
+ remember: {
51
+ type: "string",
52
+ description:
53
+ "Name this extraction so it can be replayed later, as 'name' or 'name/variant'. Optional: a spec that produced clean rows is remembered anyway, under a name derived from its fields and a variant derived from the clicks, fills and scrolls that preceded it. Nothing is stored from a result that fails the quality bar.",
54
+ },
55
+ };
56
+
35
57
  const FINGERPRINT = {
36
58
  fingerprint: {
37
59
  type: "object",
@@ -120,7 +142,7 @@ const BROWSER_TOOLS = [
120
142
  {
121
143
  name: "browser_extract",
122
144
  description:
123
- "Extract repeating records (cards, rows, listings) with fields grouped per record. Fields resolve INSIDE each record root and a missing field yields null instead of shifting later records' values. Returns fill rates and warns when a field is empty inside the record scope but matches page-wide (record boundary too narrow).",
145
+ "Extract repeating records (cards, rows, listings) with fields grouped per record. Fields resolve INSIDE each record root and a missing field yields null instead of shifting later records' values. Returns fill rates and warns when a field is empty inside the record scope but matches page-wide (record boundary too narrow). `record` and `fields` are optional when a recipe has already been learned for this page shape: omit them to replay it, and the result names it in `used_recipe` (with `stale: true` if the page no longer matches what was learned). `remember` names what a fresh spec is stored as.",
124
146
  inputSchema: {
125
147
  type: "object",
126
148
  properties: {
@@ -157,16 +179,20 @@ const BROWSER_TOOLS = [
157
179
  description:
158
180
  "Page-wide re-check of any field that came back entirely empty (default true)",
159
181
  },
182
+ ...RECIPE,
160
183
  ...SINK,
161
184
  ...TARGET,
162
185
  },
163
- required: ["record", "fields"],
186
+ // record/fields are not required: with neither, a recipe learned on this
187
+ // page shape supplies them. Nothing known for the page is an error that
188
+ // says so, never a spec-less extract.
189
+ required: [],
164
190
  },
165
191
  },
166
192
  {
167
193
  name: "browser_extract_all",
168
194
  description:
169
- "Paginate and extract in one call, with no model round-trip per page. Takes browser_extract's spec plus a URL template, walks pages, dedups on a key, and halts on: limit reached, empty page, a page whose records repeat an earlier page's (the trap where ignored page-size params silently return page 1 again), fill rates collapsing against page 1's baseline, or max_pages. Always reports which condition fired and returns everything collected so far.",
195
+ "Paginate and extract in one call, with no model round-trip per page. Takes browser_extract's spec plus a URL template — the spec is optional when a recipe was learned for that page shape, and a recipe learned here stores the template so a later call can replay both. Walks pages, dedups on a key, and halts on: limit reached, empty page, a page whose records repeat an earlier page's (the trap where ignored page-size params silently return page 1 again), fill rates collapsing against page 1's baseline, or max_pages. Always reports which condition fired and returns everything collected so far.",
170
196
  inputSchema: {
171
197
  type: "object",
172
198
  properties: {
@@ -203,12 +229,16 @@ const BROWSER_TOOLS = [
203
229
  "Halt when a field well-populated on the baseline page falls below this fraction of it (default 0.5). 0 disables the check.",
204
230
  },
205
231
  max_text: { type: "number" },
232
+ ...RECIPE,
206
233
  ...SINK,
207
234
  // Session only, deliberately: this tool drives its own navigation from
208
235
  // url_template, so a tabId would be accepted and then ignored.
209
236
  session: TARGET.session,
210
237
  },
211
- required: ["url_template", "record", "fields"],
238
+ // Same as browser_extract: the spec is optional when a recipe exists for
239
+ // the page shape url_template points at. The template itself is not —
240
+ // it is what says which pages to walk.
241
+ required: ["url_template"],
212
242
  },
213
243
  },
214
244
  {
@@ -418,7 +448,7 @@ const BROWSER_TOOLS = [
418
448
  {
419
449
  name: "browser_get_site_memory",
420
450
  description:
421
- "Get navigation memory, obstacles, and fixes for a specific website domain",
451
+ "Get navigation memory for a website domain: the obstacles and fixes saved for it, plus any extraction recipes learned there — their fields, their variants, and the steps that were observed before each one worked. The steps are observations, not a script: reissue one only if it still fits the page.",
422
452
  inputSchema: {
423
453
  type: "object",
424
454
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poltertab",
3
- "version": "1.6.0-beta.1",
3
+ "version": "1.6.0-beta.2",
4
4
  "description": "Let any AI assistant drive and scrape your existing Chrome profile — no headless browser, no complex setup.",
5
5
  "bin": {
6
6
  "poltertab": "./bin/poltertab.js"