Skip to content

feat: add Yutori integration (browsing agent, research, scouts)#20384

Open
deviparikh wants to merge 22 commits intoPipedreamHQ:masterfrom
deviparikh:feat/yutori-integration
Open

feat: add Yutori integration (browsing agent, research, scouts)#20384
deviparikh wants to merge 22 commits intoPipedreamHQ:masterfrom
deviparikh:feat/yutori-integration

Conversation

@deviparikh
Copy link
Copy Markdown

@deviparikh deviparikh commented Mar 25, 2026

Resolves #20387

Summary

This PR adds Yutori as a new native integration to the Pipedream registry.

Yutori is reimagining how people interact with the web. The Yutori API is an AI web agent platform. Give it a task and it navigates websites, fills forms, extracts data, and completes multi-step workflows using a real cloud browser — or runs deep research across 100+ sources. You can also set up Scouts: recurring monitors that watch any part of the web on a schedule and alert you when something relevant happens.

Components included

Actions (11):

  • Run Browsing Task — launch a cloud browser agent to navigate a site, fill forms, or extract data
  • Get Browsing Task Result — fetch the status and result of a previously started browsing task
  • Run Research Task — start a deep web research task across 100+ sources
  • Get Research Task Result — fetch the status and result of a previously started research task
  • Create Scout — create a recurring web monitor that runs on a schedule
  • List Scouts — list all scouts with IDs, status, and configuration
  • Get Scout — fetch details and current status of a specific scout
  • Get Scout Updates — fetch the latest findings from a specific scout on demand
  • Mark Scout as Done — archive a scout and stop it from running
  • Restart Scout — reactivate a previously archived scout
  • Delete Scout — permanently delete a scout and all its findings

Triggers / Sources (1):

  • New Scout Update — polls every 15 minutes for new findings across all scouts; supports hoursBack lookback on first run and uses dedupe: "unique" with cursor-based pagination

Checklist

  • version: "0.0.1" on all components
  • annotations block on all components (openWorldHint, destructiveHint, readOnlyHint)
  • dedupe: "unique" on polling source
  • Logo (yutori.svg) included
  • README with Overview, Example Use Cases, Getting Started, Troubleshooting sections
  • No .DS_Store or other build artifacts

Summary by CodeRabbit

  • New Features
    • Yutori integration: create, list, get, restart, mark-done, and delete recurring web monitors (“Scouts”); run and fetch browsing & research tasks; polling source that emits one event per new scout update
  • Tests
    • Added a test event payload for the New Scout Update source
  • Chores
    • Added runtime dependency for the Yutori package
  • Style
    • Added trailing newlines to several component files

Adds Yutori to the Pipedream registry: 11 actions covering browsing, research, and full scout lifecycle management, plus a polling trigger that fires when any scout produces new findings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
pipedream-docs-redirect-do-not-edit Ignored Ignored Apr 21, 2026 0:13am

Request Review

@pipedream-component-development
Copy link
Copy Markdown
Collaborator

Thank you so much for submitting this! We've added it to our backlog to review, and our team has been notified.

@pipedream-component-development
Copy link
Copy Markdown
Collaborator

Thanks for submitting this PR! When we review PRs, we follow the Pipedream component guidelines. If you're not familiar, here's a quick checklist:

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Yutori integration: an authenticated app client, 11 actions for browsing/research tasks and scout CRUD/management, a polling source emitting scout updates with stateful timestamping and pagination, a test event fixture, and a package.json dependency update.

Changes

Cohort / File(s) Summary
App Integration & Package
components/yutori/yutori.app.mjs, components/yutori/package.json
New Yutori app client with base URL, auth header helper, generic _request, and methods for browsing/research tasks and scout CRUD/updates. package.json adds @pipedream/platform: ^3.1.1.
Scout CRUD & Management Actions
components/yutori/actions/create-scout/create-scout.mjs, components/yutori/actions/delete-scout/delete-scout.mjs, components/yutori/actions/get-scout/get-scout.mjs, components/yutori/actions/list-scouts/list-scouts.mjs, components/yutori/actions/mark-scout-done/mark-scout-done.mjs, components/yutori/actions/restart-scout/restart-scout.mjs, components/yutori/actions/get-scout-updates/get-scout-updates.mjs
Adds actions for create, delete, get, list, mark-done, restart, and fetch scout updates. Actions build payloads/params, call app methods, set $summary, and return API results.
Task Run & Result Actions
components/yutori/actions/run-browsing-task/run-browsing-task.mjs, components/yutori/actions/get-browsing-task-result/get-browsing-task-result.mjs, components/yutori/actions/run-research-task/run-research-task.mjs, components/yutori/actions/get-research-task-result/get-research-task-result.mjs
Adds actions to start browsing/research tasks (payload assembly with optional webhook/maxSteps) and read-only actions to fetch task results by taskId, exporting status summaries.
Polling Source & Fixture
components/yutori/sources/new-scout-update/new-scout-update.mjs, components/yutori/sources/new-scout-update/test-event.mjs
New polling source that tracks lastTimestamp in db, computes sinceTimestamp (honors hoursBack), pages through getUpdates with cursor and MAX_PAGES and seen-cursor guard, emits events oldest-first, and advances stored timestamp only when pagination completes; includes test event fixture.
Whitespace / EOF Normalization
components/awardco/awardco.app.mjs, components/beehiv/beehiv.app.mjs, components/certs365/certs365.app.mjs, components/sunshine_conversations/sunshine_conversations.app.mjs, components/yuroti/yuroti.app.mjs
Added trailing newlines at EOF in multiple existing app files; no behavioral changes.

Sequence Diagrams

sequenceDiagram
    participant Workflow as Workflow/User
    participant Action as Action (step)
    participant App as Yutori App
    participant API as Yutori API

    Workflow->>Action: invoke action (e.g., create-scout / run-research-task)
    Action->>App: call method (createScout/createResearchTask/createBrowsingTask)
    App->>API: HTTP POST /scouts or /research_tasks or /browsing_tasks
    API-->>App: returns resource
    App-->>Action: result
    Action->>Workflow: return result and export "$summary"
Loading
sequenceDiagram
    participant Source as Polling Source
    participant DB as State DB
    participant App as Yutori App
    participant API as Yutori API
    participant Sink as Event Sink

    Source->>DB: _getLastTimestamp()
    DB-->>Source: lastTimestamp or null
    Source->>App: getUpdates(since=sinceTimestamp / cursor)
    App->>API: GET /updates?since=... or ?cursor=...
    API-->>App: {updates[], cursor}
    loop paginate (up to MAX_PAGES)
        App->>API: GET /updates?cursor=cursor
        API-->>App: {updates[], cursor}
    end
    Source->>Sink: emit events (oldest first)
    Source->>DB: _setLastTimestamp(newTs) [only if not truncated]
    DB-->>Source: ok
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested labels

ai-assisted

Suggested reviewers

  • lcaresia
  • GTFalcao
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: add Yutori integration (browsing agent, research, scouts)' is clear, concise, and accurately describes the main change: adding a comprehensive Yutori integration with multiple components.
Description check ✅ Passed The PR description is comprehensive and well-structured, including a summary of the Yutori service, detailed component listings (11 actions and 1 polling source), checklist items confirming compliance with standards, and proper linkage to issue #20387.
Linked Issues check ✅ Passed The PR addresses all coding objectives from issue #20387: 11 action components are implemented (browsing/research tasks with status checks; scout management and operations), the polling source with proper cursor pagination and deduplication is included, and version/annotation requirements are met.
Out of Scope Changes check ✅ Passed All changes are scoped to the Yutori integration or formatting fixes. The Yutori app definition and 12 components address the linked issue; trailing newlines in other app files are minor formatting corrections unrelated to functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/yutori/actions/create-scout/create-scout.mjs`:
- Around line 49-55: The "Flat" option currently shows label "Flat" while its
value is "zapier", which can confuse users; update the options array entry that
has value "zapier" (the object with label "Flat" and value "zapier" inside the
options list) to a clearer label such as "Flat (Zapier‑compatible)" so the UI
and payload value are unambiguous; similarly, if needed, adjust the description
string (the description property near default "scout") to mention "Flat
(Zapier‑compatible)" so all references match.

In `@components/yutori/actions/list-scouts/list-scouts.mjs`:
- Around line 26-28: The condition in the run method always evaluates true
because pageSize has a default (50); remove the conditional and always set
params.page_size to this.pageSize (in the async run({ $ }) function) so
params.page_size is consistently populated — update the params construction
around pageSize instead of using if (this.pageSize).

In `@components/yutori/actions/mark-scout-done/mark-scout-done.mjs`:
- Around line 9-13: The annotations object in mark-scout-done.mjs currently sets
destructiveHint: false but this action permanently halts a running scout; change
annotations.destructiveHint to true to reflect that behavior (locate the
annotations block in the mark-scout-done module), update any related
comments/tests/docs referencing the old value, and run the action's consumer
checks to ensure downstream UI/AI agents pick up the new hint.

In `@components/yutori/actions/run-browsing-task/run-browsing-task.mjs`:
- Around line 40-45: The condition in the run method that checks "if
(this.maxSteps)" is redundant because maxSteps has a default (50) and is always
truthy; remove the conditional and always set payload.max_steps from
this.maxSteps when building the payload in async run({ $ }) (i.e.,
unconditionally assign max_steps alongside task and start_url), updating the
payload creation in run to include this.maxSteps directly.

In `@components/yutori/sources/new-scout-update/new-scout-update.mjs`:
- Around line 35-37: The _getLastTimestamp() method currently returns
this.db.get("lastTimestamp") || null which treats 0 as missing; change it to use
the nullish coalescing operator (this.db.get("lastTimestamp") ?? null) so zero
is preserved, and anywhere you check the retrieved value (the later check around
the sinceTimestamp handling at lines referenced) replace the falsy check if
(!sinceTimestamp) with an explicit null/undefined check (e.g., if
(sinceTimestamp == null) or if (sinceTimestamp === null)) so numeric 0 is not
treated as absent.
- Around line 57-67: The polling loop that calls this.yutori.getUpdates trusts
response.next_cursor and can loop forever if the API repeats or never clears the
cursor; modify the loop in new-scout-update.mjs to (1) track seen cursors (e.g.,
a Set seenCursors) and break if a cursor repeats, (2) enforce a hard page limit
(e.g., const MAX_PAGES = 100) and break when reached, and (3) also break if the
returned page is empty; apply these checks around the existing cursor handling
and updates.push(...) so getUpdates, cursor, updates, sinceTimestamp and now are
used unchanged but the loop will terminate safely.

In `@components/yutori/yutori.app.mjs`:
- Around line 57-61: Path parameters like taskId and scoutId are interpolated
raw into endpoint paths (e.g., in getBrowsingTask and other methods that call
this._request with paths like `/browsing/tasks/${taskId}` or
`/browsing/scouts/${scoutId}`), which can break routing if they contain reserved
characters; update all such callers to URL-encode dynamic segments using
encodeURIComponent before constructing the path so the request path is safe and
correct (locate every method that builds a path with `${taskId}` or `${scoutId}`
and replace the raw interpolation with the encoded value).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6abf41cb-d89a-44fc-8d21-5ebd6263ab55

📥 Commits

Reviewing files that changed from the base of the PR and between 2f30f38 and 2725c7f.

⛔ Files ignored due to path filters (1)
  • components/yutori/yutori.svg is excluded by !**/*.svg
📒 Files selected for processing (15)
  • components/yutori/actions/create-scout/create-scout.mjs
  • components/yutori/actions/delete-scout/delete-scout.mjs
  • components/yutori/actions/get-browsing-task-result/get-browsing-task-result.mjs
  • components/yutori/actions/get-research-task-result/get-research-task-result.mjs
  • components/yutori/actions/get-scout-updates/get-scout-updates.mjs
  • components/yutori/actions/get-scout/get-scout.mjs
  • components/yutori/actions/list-scouts/list-scouts.mjs
  • components/yutori/actions/mark-scout-done/mark-scout-done.mjs
  • components/yutori/actions/restart-scout/restart-scout.mjs
  • components/yutori/actions/run-browsing-task/run-browsing-task.mjs
  • components/yutori/actions/run-research-task/run-research-task.mjs
  • components/yutori/package.json
  • components/yutori/sources/new-scout-update/new-scout-update.mjs
  • components/yutori/sources/new-scout-update/test-event.mjs
  • components/yutori/yutori.app.mjs

Comment thread components/yutori/actions/create-scout/create-scout.mjs Outdated
Comment thread components/yutori/actions/list-scouts/list-scouts.mjs Outdated
Comment thread components/yutori/actions/mark-scout-done/mark-scout-done.mjs Outdated
Comment thread components/yutori/actions/run-browsing-task/run-browsing-task.mjs Outdated
Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs
Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs
Comment thread components/yutori/yutori.app.mjs
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
components/yutori/sources/new-scout-update/new-scout-update.mjs (1)

60-73: 🧹 Nitpick | 🔵 Trivial

Consider breaking on empty page for efficiency.

The pagination loop correctly guards against infinite loops with MAX_PAGES and seenCursors. However, if the API returns an empty page with a cursor, the loop will continue fetching until hitting MAX_PAGES. Breaking early on empty pages could reduce unnecessary API calls.

♻️ Optional optimization
       const page = response?.updates ?? [];
+      if (page.length === 0) break;
       updates.push(...page);
       cursor = response?.next_cursor ?? null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/yutori/sources/new-scout-update/new-scout-update.mjs` around lines
60 - 73, The pagination loop in the do/while that calls this.yutori.getUpdates
can continue fetching when the API returns an empty page with a non-null cursor;
after retrieving page (const page = response?.updates ?? []), if page.length ===
0 break the loop to avoid unnecessary API calls, while preserving existing
guards (pages, MAX_PAGES, seenCursors and cursor handling) and still pushing
non-empty pages into updates; ensure this check occurs before setting cursor =
response?.next_cursor to keep seenCursors logic consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@components/yutori/sources/new-scout-update/new-scout-update.mjs`:
- Around line 60-73: The pagination loop in the do/while that calls
this.yutori.getUpdates can continue fetching when the API returns an empty page
with a non-null cursor; after retrieving page (const page = response?.updates ??
[]), if page.length === 0 break the loop to avoid unnecessary API calls, while
preserving existing guards (pages, MAX_PAGES, seenCursors and cursor handling)
and still pushing non-empty pages into updates; ensure this check occurs before
setting cursor = response?.next_cursor to keep seenCursors logic consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d4017b7c-be19-425e-ab38-0d52904bdf3c

📥 Commits

Reviewing files that changed from the base of the PR and between 2725c7f and 3d8763e.

📒 Files selected for processing (5)
  • components/yutori/actions/create-scout/create-scout.mjs
  • components/yutori/actions/list-scouts/list-scouts.mjs
  • components/yutori/actions/run-browsing-task/run-browsing-task.mjs
  • components/yutori/sources/new-scout-update/new-scout-update.mjs
  • components/yutori/yutori.app.mjs

@GTFalcao
Copy link
Copy Markdown
Collaborator

Hi, please submit an app integration request in our issues (https://github.com/PipedreamHQ/pipedream/issues). The app needs to be integrated into the platform with proper authentication mechanisms before any components can be reviewed and merged.

@deviparikh
Copy link
Copy Markdown
Author

Thanks for the heads up! We've submitted the app integration request here: #20387. Happy to provide any additional information needed to get the authentication set up. We'll keep this PR open and ready to go once the app is integrated.

@sergio-eliot-rodriguez
Copy link
Copy Markdown
Collaborator

Resolves #20387

Copy link
Copy Markdown
Collaborator

@GTFalcao GTFalcao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @deviparikh , a few comments:

  • there are conflicts to be resolved since the app was integrated after this PR was submitted;
  • if possible, please run npx pnpm install and npx eslint --fix components/yutori as these are needed for the PR's automated checks to succeed;
  • the logo image file can be safely removed from the PR, it has already been added to the integrated app;

- Resolve add/add conflict in package.json (take version 0.0.1 from upstream, keep our dependencies block, merge keywords)
- Resolve add/add conflict in yutori.app.mjs (keep our full implementation, discard upstream placeholder stub)
- Remove yutori.svg (logo already added by Pipedream team)
- Fix source description to start with "Emit new" per Pipedream linting guidelines
@deviparikh
Copy link
Copy Markdown
Author

Thanks for the thorough review @GTFalcao! Addressed all three items in 90ba9c6:

  • Resolved both merge conflicts (kept our full yutori.app.mjs implementation, merged package.json cleanly with upstream version + keywords)
  • Removed yutori.svg since the logo is already on your side
  • Fixed source description to start with "Emit new" per linting guidelines
  • Re-ran pnpm install and eslint --fix — zero errors

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/yuroti/yuroti.app.mjs (1)

1-11: ⚠️ Potential issue | 🔴 Critical

Critical: The "yuroti" directory and files should not exist - use "yutori" instead.

The codebase currently contains two directories: components/yuroti/ (incorrect spelling) and components/yutori/ (correct spelling with full implementation). The Yutori platform documentation confirms the correct spelling is "Yutori" (https://yutori.com, https://docs.yutori.com).

Remove the components/yuroti/ directory and all its files. All integration code should use the components/yutori/ directory and naming throughout (directory name, filenames, package.json, and app ID).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/yuroti/yuroti.app.mjs` around lines 1 - 11, This file and
directory use the incorrect "yuroti" spelling; delete the entire
components/yuroti/ directory and its files, rename or recreate them under
components/yutori/, and update the exported app identifier and any references
from "yuroti" to "yutori" (e.g., in components/yuroti/yuroti.app.mjs change
export default { app: "yuroti", ... } to use "yutori" and move the file to
components/yutori/yutori.app.mjs), then search the repo for any remaining
"yuroti" occurrences (filenames, package.json, imports, app IDs, and tests) and
replace them with "yutori" to ensure all integration code uses the correct
spelling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/yutori/sources/new-scout-update/new-scout-update.mjs`:
- Line 61: When pagination stops because MAX_PAGES was hit, do not advance
lastTimestamp (which would drop unprocessed older updates); instead only update
lastTimestamp = updates[0].timestamp + 1 when pagination completed normally (no
next_cursor) or when you did not hit the MAX_PAGES limit. Change the two places
that set lastTimestamp (the block using pages/next_cursor around pages++ and the
later block at lines 89-93) to check whether pagination was truncated (e.g.,
pagesReached = pages >= MAX_PAGES && next_cursor) and skip advancing
lastTimestamp when pagesReached is true; otherwise advance as before.

---

Outside diff comments:
In `@components/yuroti/yuroti.app.mjs`:
- Around line 1-11: This file and directory use the incorrect "yuroti" spelling;
delete the entire components/yuroti/ directory and its files, rename or recreate
them under components/yutori/, and update the exported app identifier and any
references from "yuroti" to "yutori" (e.g., in components/yuroti/yuroti.app.mjs
change export default { app: "yuroti", ... } to use "yutori" and move the file
to components/yutori/yutori.app.mjs), then search the repo for any remaining
"yuroti" occurrences (filenames, package.json, imports, app IDs, and tests) and
replace them with "yutori" to ensure all integration code uses the correct
spelling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b398ec4d-2642-4b53-b527-7f092a6ddc6c

📥 Commits

Reviewing files that changed from the base of the PR and between 3d8763e and 90ba9c6.

📒 Files selected for processing (7)
  • components/awardco/awardco.app.mjs
  • components/beehiv/beehiv.app.mjs
  • components/certs365/certs365.app.mjs
  • components/sunshine_conversations/sunshine_conversations.app.mjs
  • components/yuroti/yuroti.app.mjs
  • components/yutori/package.json
  • components/yutori/sources/new-scout-update/new-scout-update.mjs

Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs Outdated
If MAX_PAGES is reached while next_cursor is still set, leave lastTimestamp
unchanged so the next poll retries from the same window instead of silently
dropping unprocessed updates.
@deviparikh
Copy link
Copy Markdown
Author

Re: the components/yuroti/ directory — that was introduced upstream by the Pipedream team as part of the app integration (not part of our PR's changes), so we'll leave it as-is on our end. Worth noting there's a typo though: it should be yutori, not yuroti. Happy to defer to the team on how to handle that!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/yutori/sources/new-scout-update/new-scout-update.mjs`:
- Around line 69-71: The current cursor-advance logic assumes getUpdates returns
numeric, reverse-chronological timestamps and uses updates[0].timestamp + 1;
instead, normalize and validate timestamps from this.yutori.getUpdates by
converting each update.timestamp to a numeric epoch (e.g., Date.parse/new
Date(...).getTime()), handle ISO strings or numbers uniformly, and compute the
next cursor by taking the maximum numeric timestamp across all merged paginated
responses (after normalizing) and adding 1; also re-sort or validate ordering if
you rely on order elsewhere and replace any uses of updates[0].timestamp with
the computed maxTimestamp to advance state (references: this.yutori.getUpdates,
updates array, and the cursor-advance logic that uses updates[0].timestamp).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f5bde445-b9e0-4d1e-8185-8a36b8cc332a

📥 Commits

Reviewing files that changed from the base of the PR and between 90ba9c6 and 0792ba7.

📒 Files selected for processing (1)
  • components/yutori/sources/new-scout-update/new-scout-update.mjs

Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs Outdated
… ordering

Add toEpochMs() to handle both numeric and ISO string timestamps.
Sort updates explicitly oldest-first before emitting instead of relying
on API returning reverse-chronological order. Derive next lastTimestamp
from max(all timestamps) rather than updates[0].
@deviparikh
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/yutori/sources/new-scout-update/new-scout-update.mjs`:
- Around line 97-103: The emitted event metadata uses update.timestamp which may
be an ISO string; convert it to a numeric epoch (milliseconds since Unix epoch)
before emitting to ensure consistent ordering. In the loop over orderedUpdates
where this.$emit(...) is called, coerce update.timestamp to a Number (e.g.,
Date.parse or new Date(...).getTime()) and pass that numeric value as ts instead
of the raw update.timestamp so all emitted events have numeric ts values.
- Around line 69-81: The loop assumes response.updates is valid and may advance
state even when the API returns an unexpected shape; add a defensive check after
calling this.yutori.getUpdates to ensure response?.updates is an array (e.g.,
Array.isArray(response.updates)); if not, log a warning/error including the raw
response and break or return so you do not advance cursor/lastTimestamp; keep
using response?.next_cursor only when the updates array is valid. Reference
symbols: this.yutori.getUpdates, response, response.updates, cursor, updates,
lastTimestamp/sinceTimestamp.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 41d6f1fd-fbf3-4367-a674-1d13141798f3

📥 Commits

Reviewing files that changed from the base of the PR and between 0792ba7 and 2c9dae0.

📒 Files selected for processing (1)
  • components/yutori/sources/new-scout-update/new-scout-update.mjs

Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs Outdated
Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs
@deviparikh
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/yutori/sources/new-scout-update/new-scout-update.mjs`:
- Around line 83-87: The toEpochMs helper currently treats numeric-looking
strings like "1700000000000" as non-parsable (Date.parse returns NaN) and
throws; update toEpochMs to explicitly handle numeric timestamp strings by
checking if value is a string of digits (e.g., /^\d+$/) and returning
Number(value) for those cases, otherwise fall back to Date.parse and the
existing error path; reference the toEpochMs function to locate and update this
logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: efe85777-1832-495a-aa8a-d7c932f828bb

📥 Commits

Reviewing files that changed from the base of the PR and between 0792ba7 and b89254a.

📒 Files selected for processing (1)
  • components/yutori/sources/new-scout-update/new-scout-update.mjs

Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs Outdated
@deviparikh
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Collaborator

@GTFalcao GTFalcao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your updates @deviparikh , looks mostly good to me.

I'm just wondering why creating/deleting a scout is being done as actions rather than a webhook source which would seem more appropriate. Let me know if there's a specific reason for that or whether it can be simplified into a webhook source instead, and we can move forward.

Also, from some whitespace patterns I can tell eslint is not being applied properly - which is why the automated checks are failing. Normally it runs on a husky hook if you have dependencies installed on the repo, though you can manually run it with npx eslint --fix components/yutori as I mentioned before. If you're having issues with this, please give me write access to your fork and I can run it for you.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like it would make more sense as a source, not as an action, if the purpose is to create a webhook - the scout creation would be handled on source deployment, using the source's own http URL.

Is there a specific reason why this is being created as an action instead?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the source model, this would be done when disabling the source.

Comment thread components/yutori/package.json Outdated
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"version": "0.1.0",

…te on disable)

- add activate() hook: creates the scout from source props on deploy
- add deactivate() hook: deletes the scout when source is disabled
- switch polling from getUpdates() (all scouts) to getScoutUpdates(scoutId)
- add scout config props: query, outputInterval, userTimezone, userLocation, skipEmail
- default skipEmail=true since Pipedream steps handle notifications
- bump version to 0.1.0
- update create-scout description to clarify standalone vs. source use cases
Scout lifecycle (create on deploy, delete on disable) is now handled
entirely by the new-scout-update source hooks.
…facing README

These actions only make sense when scouts are managed independently on the Yutori
platform. With the lifecycle source model, scout management happens entirely in
Pipedream via deploy/disable.
@deviparikh
Copy link
Copy Markdown
Author

deviparikh commented Apr 3, 2026

Thanks, this makes sense.

I updated the integration to follow the source lifecycle model you suggested:

  • removed the standalone scout lifecycle actions
  • moved scout creation into activate() and deletion into deactivate()
  • scoped New Scout Update to the scout it creates
  • bumped the package version to 0.1.0

I also fixed the source polling logic to match the per-scout updates API and made cleanup tolerant of the scout already being deleted.

@deviparikh
Copy link
Copy Markdown
Author

@GTFalcao let me know if you have any additional feedback.

@deviparikh deviparikh requested a review from GTFalcao April 9, 2026 17:17
@deviparikh
Copy link
Copy Markdown
Author

deviparikh commented Apr 20, 2026

Merged the latest master into this branch and resolved the current conflicts on April 20, 2026.

Also re-ran pnpm install and npx eslint --fix components/yutori after the merge. The branch is updated.

Copy link
Copy Markdown
Collaborator

@GTFalcao GTFalcao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your attention to making the required changes! The components look good. The remaining comments are simple to address (I left commitable suggestions for almost all). Moving this forward to the QA stage

Comment thread components/yutori/actions/get-scout/get-scout.mjs Outdated
Comment thread components/yutori/actions/get-scout-updates/get-scout-updates.mjs Outdated
Comment thread components/yutori/actions/get-research-task-result/get-research-task-result.mjs Outdated
Comment thread components/yutori/actions/get-browsing-task-result/get-browsing-task-result.mjs Outdated
Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs Outdated
Comment thread components/yutori/sources/new-scout-update/new-scout-update.mjs Outdated
Comment thread components/yutori/README.md Outdated
deviparikh and others added 7 commits April 20, 2026 17:06
Co-authored-by: Guilherme Falcão <48412907+GTFalcao@users.noreply.github.com>
Co-authored-by: Guilherme Falcão <48412907+GTFalcao@users.noreply.github.com>
…h-task-result.mjs

Co-authored-by: Guilherme Falcão <48412907+GTFalcao@users.noreply.github.com>
Co-authored-by: Guilherme Falcão <48412907+GTFalcao@users.noreply.github.com>
Co-authored-by: Guilherme Falcão <48412907+GTFalcao@users.noreply.github.com>
…g-task-result.mjs

Co-authored-by: Guilherme Falcão <48412907+GTFalcao@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

User submitted Submitted by a user

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[APP] Yutori — AI web agent platform (browsing, research, scouts)

6 participants