2184 Commits

Author SHA1 Message Date
amhsirak 48b4675e95 fix: address review on AI Extract
- Keep aiExtract (spec and scraped sample rows) out of the robot-created
  telemetry event, in the app and SDK routes.
- Send OLLAMA_API_KEY only to the operator's Ollama endpoint, not to a
  base URL chosen per request; a key given with the request is still sent.
- Reset the common-class cache with the path cache per list, so field
  XPaths aren't built from another list's classes.
- ENVEXAMPLE: use host.docker.internal for Ollama, as Docker Compose does.
- AI Extract tests fail when Chromium can't launch; AI_EXTRACT_SKIP_BROWSER=1
  skips them explicitly.
- SDK extract/llm: generation failures return 400 again, as before.

Signed-off-by: amhsirak <karishmashuklaa@gmail.com>
2026-10-17 13:20:17 +00:00
Claude 708b7221c4 fix: find next-page controls the generic detector misses
"Extract 15 products" still returned 12: the generic pagination detector
found nothing. Its patterns miss common markups, e.g. "Next →" / "Next »"
(the arrow breaks the /^next$/ match) and numbered pages without a Next
link, and it never looks at rel="next".

AI Extract now tries its own finder first (findNextPageControl in
aiExtractPage.js), then the generic detector:
- rel="next" links
- Next / Load more controls, ignoring arrows, preferring ones inside a
  pagination container; disabled controls are skipped
- the link after the current page number (aria-current="page" or an
  active/current marker)
Selectors are comma-free (the runtime splits on commas), checked to match
the chosen control, and must stay on the same site. Every decision is
logged, including the pagination labels seen when nothing matches.

Tests cover "Next →", numbered-only and arrow-only rel=next markup, each
replayed across pages in maxun-core's interpreter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LCfkReTCeeFhy3mGCQYNDj
2026-10-17 12:54:52 +00:00
Claude ab638069e6 feat: follow next-page pagination in AI Extract for an explicit item count
"Extract 15 products" on a page showing 12 returned 12: list robots only
allowed none/scrollDown pagination.

When the prompt asks for a specific count and the page shows fewer items
(and the page does not load more as it scrolls), the robot now uses the
page's own next-page or load-more control, capped at the requested count.

- Detection only reads the page; creating the robot still never leaves it.
- A control that links to another site is refused.
- No count, or a count the first page satisfies: no pagination.
- assertWorkflowInScope allows clickNext/clickLoadMore only when the
  scrapeList limit equals the requested count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LCfkReTCeeFhy3mGCQYNDj
2026-10-17 12:40:55 +00:00
Claude 7d3149474b fix: authenticate AI Extract to hosted Ollama and explain provider errors
AI Extract never sent an API key to Ollama and fell back to the local
default model, so Ollama Cloud answered 404 and the user only saw
"Request failed with status code 404".

- Send OLLAMA_API_KEY (or the configured key) as a Bearer token.
- Use OLLAMA_MODEL when no model is configured.
- Report the provider's own error, the URL called, and what to check.
- Document OLLAMA_BASE_URL / OLLAMA_API_KEY / OLLAMA_MODEL in ENVEXAMPLE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LCfkReTCeeFhy3mGCQYNDj
2026-10-17 12:00:03 +00:00
amhsirak 79cded098b chore: detailed error logs 2026-10-17 17:18:22 +05:30
Claude 3fa5630f40 feat: intent-first AI Extract scoped to the entered page
Port the Cloud AI Extract pipeline (getmaxun/maxun-cloud-recording#656,
#657) to OSS, adapted to the OSS provider config.

- Website URL is now required for AI Extract (UI, /storage/recordings/llm
  and /api/sdk/extract/llm); the search and multi-site fallbacks are no
  longer used.
- Extraction is driven by the prompt: prompt -> spec -> id-tagged page
  snapshot -> grounded citations -> compiled selectors verified with
  maxun-core's scraper. No fallback to group selection.
- Page scope is enforced in the browser: navigation requests to other
  documents are aborted, window.open is disabled, route changes are
  undone, cross-site redirects are refused, and generated robots may only
  use none/scrollDown pagination.
- Overlays, lazy loading and collapsed sections are revealed on the same
  page with fixed, non-model steps.
- Spec, sample rows and missing fields saved in recording_meta.aiExtract.
- Tests: npm run test:ai-extract (unit + browser integration).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LCfkReTCeeFhy3mGCQYNDj
2026-10-16 18:43:01 +00:00
Claude af09b8479b feat(ui): monitoring toggle when creating scrape and extract robots
Adds a Monitoring switch under Options for Scrape and for Extract in
both recorder and AI mode. Scrape and AI robots get compareRuns set
right after they are created; recorder robots carry it to the save in
the recording tab, which stores it on the new robot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hskm8VdJhy1krbeJZMXCcS
2026-10-16 17:38:48 +00:00
Karishma Shukla 557b28102f Merge pull request #1244 from getmaxun/perf/scrape-quality
fix(documents): keep header fields, use PDF tables, survive cut-off answers
2026-10-16 15:04:18 +05:30
Karishma Shukla 8c065a20af Merge pull request #1246 from getmaxun/show-prompt
chore(swagger): update metadata + add tags
2026-10-16 14:59:14 +05:30
amhsirak 25179bc452 feat: add tags 2026-10-16 14:51:14 +05:30
amhsirak b594a2ca4d chore: lint 2026-10-16 14:42:03 +05:30
amhsirak 03dd71c2ac feat: link docs to desc 2026-10-16 14:41:30 +05:30
amhsirak 5b51ac5ef4 feat: link docs to desc 2026-10-16 14:40:13 +05:30
Claude d777850044 fix(documents): split oversized pages fully instead of capping at 20 segments
A page over 20 segments put the rest of the page in the last one, which
the prompt then cut, so a large CSV or sheet silently lost its tail
(a 6,000-row CSV came back with 2,302 rows). Pages are now split into as
many segments as they need, as multi-page documents already are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hskm8VdJhy1krbeJZMXCcS
2026-10-16 09:06:43 +00:00
amhsirak 99704af39b fix: rename to Maxun API 2026-10-16 14:35:23 +05:30
Claude 8bca23e99c fix(documents): address review on chunk sizing, retries and JSON salvage
- buildChunks counts each unit's label and separator against the budget;
  the prompt's chunk cap is now a safety net above it, so packed chunks
  no longer lose their last rows.
- Retry halves of a cut-off chunk run one at a time, keeping requests
  within EXTRACTION_CONCURRENCY.
- salvageTruncatedJson cuts only between array elements or top-level
  fields, so a record cut mid-way is dropped instead of kept with
  missing fields.
- extractBalancedJson skips brackets in prose ("[see notes]") and only
  treats an unclosed JSON-looking value as cut-off output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hskm8VdJhy1krbeJZMXCcS
2026-10-16 08:53:17 +00:00
Claude e390d9c620 fix(documents): wire table-aware parsing and cut-off recovery into extraction
Completes the port of the document extraction fixes: the helpers were
added but not used yet.

- Chunking: split oversized pages (CSV/DOCX are one page), repeat table
  headers across chunks, label sheets, size record chunks from the
  document's own table rows.
- Providers: report hitting the output limit (Ollama done_reason, OpenAI
  finish_reason, Anthropic stop_reason) and salvage the complete JSON.
- Extraction: chunks run 3 at a time, unwrap envelopes, re-extract
  cut-off chunks in halves (up to 3 levels), tables only as context for
  single-chunk documents, part N of M prompts with the JSON shape.
- PDF: per-page tables from pdf-parse laid out in place.
- XLSX/CSV: one Markdown table per sheet. DOCX: Markdown with tables.
- Markdown/HTML output rendered from page blocks.
- Schema prompt models repeated records as an array of objects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hskm8VdJhy1krbeJZMXCcS
2026-10-16 08:34:47 +00:00
amhsirak 94fe8d9b54 fix(documents): keep header fields, use PDF tables, survive cut-off answers 2026-10-16 13:57:06 +05:30
amhsirak 8757e86d54 perf(crawl): skip non-page links, clean capture, ignore tracker requests 2026-10-16 13:04:53 +05:30
amhsirak 147492f674 perf(scrape): main-content isolation, single page snapshot, live DOM left intact 2026-10-16 12:15:25 +05:30
amhsirak 5a264e6c40 feat: store llm extract prompt 2026-10-16 00:50:51 +05:30
amhsirak 2f26e4d975 feat: return snake_case keys for captured data in API responses 2026-10-15 23:40:13 +05:30
Karishma 668bd863a5 Merge pull request #1227 from breken-ai/fix/gsheet-screenshot-rows
fix(gsheet): write one row per screenshot in the Screenshot sheet
2026-10-01 20:45:22 +05:30
breken-ai a53ed4dd14 fix(gsheet): write one row per screenshot in the Screenshot sheet
updateGoogleSheet passed the screenshot rows wrapped in another array,
so processOutputType flattened the array itself: the Screenshot sheet
got headers "0", "1", ... and a single row of JSON strings instead of
"Screenshot Key" / "Screenshot URL" rows. Because the column count
follows the number of screenshots, the header check also failed on
later runs and re-appended a header row.

Pass the rows array directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:08:38 -07:00
mrhard9090 75a6f9013b fix(db): add migration for run.hasChanges 2026-09-24 23:05:13 +03:00
Rohit Rajan 85ac964411 chore: add monitor feat telemetry 2026-09-16 23:41:43 +05:30
Rohit Rajan 5f270502ac fix: address coderabbit reviews 2026-09-16 18:29:05 +05:30
Rohit Rajan 546b0796fb fix: diff display cli monitoring 2026-09-16 18:06:02 +05:30
Karishma Shukla 5b4c899d34 Merge pull request #1210 from getmaxun/scrape-monitoring
feat: monitoring
2026-09-16 16:17:39 +05:30
Rohit Rajan 313bd7885d fix: rm ss comparison logic 2026-09-14 21:13:52 +05:30
Rohit Rajan 1a73e1b4fa feat: add sdk/api monitoring logic 2026-09-13 22:51:35 +05:30
Rohit Rajan c9ce803eb1 fix: click action url safeguards 2026-09-13 13:23:10 +05:30
Rohit Rajan 7ef6ee7c58 fix: register click with url 2026-09-13 13:12:14 +05:30
Rohit Rajan 1ff32d0aa8 fix: upload comparison diff extract consistency 2026-09-12 00:45:01 +05:30
Rohit Rajan 4a095ea548 fix: address coderabbit review 2026-09-12 00:33:59 +05:30
Rohit 902593cebc Merge branch 'develop' into centre-queue 2026-09-12 00:20:19 +05:30
Rohit Rajan 2e7f5b03e2 fix: centralize run queuing logic 2026-09-12 00:13:40 +05:30
Vyom Virani 223710f409 fix(server): authenticate the sockets the backend opens to itself
API, SDK and scheduled runs have hung since socket auth was added.

`authenticateSocket` is applied to every namespace via `io.on('new_namespace')`,
and it requires a token in `handshake.auth` or a `token` cookie. Browser clients
carry the httpOnly cookie, so the UI is unaffected. But the backend also joins
its own `/<browserId>` namespace as a socket.io *client* when a run is started
by something other than a browser, and that connection has neither a cookie nor
an auth token. It is refused.

The refusal is not what makes this hard to spot. `connect_error` is logged and
the socket cleaned up, but the run is never failed - so the browser eventually
falls back to a dummy socket, `ready-for-run` never reaches the caller, and the
run sits there. It reads as "slow", not as "broken".

Both server-opened connections are affected and they are the three paths people
report: `api/record.ts` (API and SDK) and `workflow-management/scheduler`
(scheduled runs).

Fixed by minting a short-lived token with the same `id` claim the HTTP login
issues, so the gate needs no special case and `socketOwns` keeps working: the
connection authenticates as the user the run already belongs to, not as a
privileged internal caller. A 60-second expiry because it is used once,
immediately - a login token is deliberately long-lived, which is right for a
session and wrong for a handshake.

Verified by A/B on one stack, same database, only the image changing:

  before   run hangs, 120s deadline exceeded
           "Socket connection error for API run ...: Unauthorized"
           "proceeding with dummy socket" -> "[SDK] Error executing robot: Run not found"
  after    run completes in 18.6s
           0 Unauthorized socket errors, 0 dummy socket fallbacks

And the gate itself, against `/queued-run`: no auth is refused, a minted token
connects, a token signed with the wrong secret is refused.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:49:42 +02:00
Rohit Rajan 1d03ddadce feat: extend monitoring to extract capture list 2026-09-10 23:25:40 +05:30
Rohit Rajan 6fd944201f feat: extend monitoring to extract cap text and ss 2026-09-10 18:40:27 +05:30
Rohit Rajan fbe730fd0c feat: extend monitoring to screenshot formats 2026-09-09 23:44:04 +05:30
Rohit Rajan 16b381e4d8 feat: extend monitoring to html,md formats 2026-09-09 23:06:39 +05:30
Ishan Karpe 03bd5d4051 Merge branch 'develop' into feature/image-ocr-support-august 2026-09-07 13:17:34 -07:00
Karishma Shukla dedd8de3d1 fix: select only necessary attributes in run comparison
Optimize query by selecting specific attributes to reduce data load.
2026-09-05 16:53:38 +05:30
Rohit Rajan 5fe3340ae3 fix: address run comparison review comments 2026-09-05 00:17:12 +05:30
jceychen 84a6f04465 Merge branch 'develop' into develop 2026-09-02 19:24:30 -07:00
joshjyu 0c44554106 fix(document): let table-only OCR results reach structured extraction 2026-08-28 09:37:52 -07:00
joshjyu 8321ee9366 fix(document): keep PaddleOCR tables when text extraction is empty 2026-08-28 09:23:24 -07:00
joshjyu 5cdff1319b fix(document): apply the email boundary to all link patterns 2026-08-28 09:21:32 -07:00
joshjyu e8209b891d fix(document): bound image size before script detection
Called downscaleIfOversized immediately after writing the temp file.
Also switched the resized dimensions from Math.round to Math.floor so the integer result cannot exceed MAX_OCR_PIXELS.
2026-08-27 23:13:21 -07:00