poltertab 1.5.0 → 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.
@@ -29,6 +29,39 @@ const SINK = {
29
29
  },
30
30
  };
31
31
 
32
+ // Self-healing: browser_click/browser_fill return the resolved element's
33
+ // fingerprint. Pass it back on a later call and, if the selector has drifted
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
+
57
+ const FINGERPRINT = {
58
+ fingerprint: {
59
+ type: "object",
60
+ description:
61
+ "Optional. The `fingerprint` object a previous browser_click/browser_fill returned for this element. When the selector no longer matches, the element is relocated by structural similarity and the result carries healed:true.",
62
+ },
63
+ };
64
+
32
65
  // Define tools
33
66
  const BROWSER_TOOLS = [
34
67
  {
@@ -45,11 +78,13 @@ const BROWSER_TOOLS = [
45
78
  },
46
79
  {
47
80
  name: "browser_click",
48
- description: "Click an element on the page",
81
+ description:
82
+ "Click an element on the page. Returns the element's `fingerprint` (pass it back later to survive a selector change) and `healed:true` if the selector had drifted and the element was relocated.",
49
83
  inputSchema: {
50
84
  type: "object",
51
85
  properties: {
52
86
  selector: { type: "string" },
87
+ ...FINGERPRINT,
53
88
  ...TARGET,
54
89
  },
55
90
  required: ["selector"],
@@ -57,13 +92,15 @@ const BROWSER_TOOLS = [
57
92
  },
58
93
  {
59
94
  name: "browser_fill",
60
- description: "Fill an input field with text",
95
+ description:
96
+ "Fill an input field with text. Returns the field's `fingerprint` (pass it back later to survive a selector change) and `healed:true` if the selector had drifted and the field was relocated.",
61
97
  inputSchema: {
62
98
  type: "object",
63
99
  properties: {
64
100
  selector: { type: "string" },
65
101
  value: { type: "string" },
66
102
  submit: { type: "boolean" },
103
+ ...FINGERPRINT,
67
104
  ...TARGET,
68
105
  },
69
106
  required: ["selector", "value"],
@@ -105,7 +142,7 @@ const BROWSER_TOOLS = [
105
142
  {
106
143
  name: "browser_extract",
107
144
  description:
108
- "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.",
109
146
  inputSchema: {
110
147
  type: "object",
111
148
  properties: {
@@ -142,16 +179,20 @@ const BROWSER_TOOLS = [
142
179
  description:
143
180
  "Page-wide re-check of any field that came back entirely empty (default true)",
144
181
  },
182
+ ...RECIPE,
145
183
  ...SINK,
146
184
  ...TARGET,
147
185
  },
148
- 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: [],
149
190
  },
150
191
  },
151
192
  {
152
193
  name: "browser_extract_all",
153
194
  description:
154
- "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.",
155
196
  inputSchema: {
156
197
  type: "object",
157
198
  properties: {
@@ -188,12 +229,16 @@ const BROWSER_TOOLS = [
188
229
  "Halt when a field well-populated on the baseline page falls below this fraction of it (default 0.5). 0 disables the check.",
189
230
  },
190
231
  max_text: { type: "number" },
232
+ ...RECIPE,
191
233
  ...SINK,
192
234
  // Session only, deliberately: this tool drives its own navigation from
193
235
  // url_template, so a tabId would be accepted and then ignored.
194
236
  session: TARGET.session,
195
237
  },
196
- 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"],
197
242
  },
198
243
  },
199
244
  {
@@ -403,7 +448,7 @@ const BROWSER_TOOLS = [
403
448
  {
404
449
  name: "browser_get_site_memory",
405
450
  description:
406
- "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.",
407
452
  inputSchema: {
408
453
  type: "object",
409
454
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poltertab",
3
- "version": "1.5.0",
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"