Skip to content

tmp: vault in sesson#682

Draft
leo-notte wants to merge 1 commit intomainfrom
feat/vault-in-session
Draft

tmp: vault in sesson#682
leo-notte wants to merge 1 commit intomainfrom
feat/vault-in-session

Conversation

@leo-notte
Copy link
Contributor

@leo-notte leo-notte commented Jan 30, 2026

Greptile Overview

Greptile Summary

This PR integrates vault (credentials) and persona support into the session layer, allowing credentials to be automatically replaced in form-filling actions.

Major changes:

  • NotteSession now accepts vault and persona parameters, with methods to read emails/SMS and attach personas
  • Vault credential replacement integrated into action execution pipeline via _action_with_vault method
  • Credential placeholder constants (EMAIL, USERNAME, PASSWORD, etc.) exposed in public API for testing
  • Duplicate PersonaTool prevention logic added in both Agent and NotteSession
  • Screenshot call guarded with null check to prevent errors when window is not initialized

Issues found:

  • Bare except clause in _has_persona_tool may hide unexpected errors
  • Inconsistency between Agent and NotteSession: Agent auto-attaches persona's vault, Session doesn't

Confidence Score: 3/5

  • Safe to merge with caution - core functionality appears sound but has error handling issues
  • The PR adds significant new functionality with mostly correct implementation, but contains a bare except clause that could hide bugs, and behavioral inconsistency between Agent and Session regarding vault attachment
  • Pay close attention to packages/notte-browser/src/notte_browser/session.py - verify error handling and vault attachment behavior

Important Files Changed

Filename Overview
packages/notte-agent/src/notte_agent/main.py Prevents duplicate PersonaTool from being added to session tools by checking persona_id
packages/notte-browser/src/notte_browser/session.py Adds vault and persona support to session with credential replacement and email/SMS methods; includes defensive screenshot check

Summary by CodeRabbit

  • New Features

    • Added persona and vault integration for session management
    • Introduced read_emails() and read_sms() methods for accessing user communication data
    • Added credential type constants (EMAIL, USERNAME, PASSWORD, MFA, CARD_NUMBER, CARD_HOLDER_NAME, CARD_EXPIRATION, CARD_CVV)
    • Enabled automatic credential replacement via vault during action execution
  • Bug Fixes

    • Fixed duplicate persona tool initialization
    • Improved screenshot capture reliability

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 30, 2026

Walkthrough

The pull request introduces persona and vault integration across multiple packages. The notte-agent package adds duplicate prevention logic to avoid creating multiple PersonaTool instances for the same persona. The notte-browser session class now accepts vault and persona as optional constructor parameters, includes methods to attach personas and manage vaults, and applies vault-based credential replacement during action execution. New convenience methods for reading emails and SMS messages are added to the session class. The notte-core credentials module exports eight credential type constants (EMAIL, USERNAME, PASSWORD, MFA, CARD_NUMBER, CARD_HOLDER_NAME, CARD_EXPIRATION, CARD_CVV), which are then re-exported at the top-level notte module for public API access.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title contains a typo ('sesson' instead of 'session') and lacks clarity about the main change; 'tmp' suggests incompleteness, making it unclear and not descriptive. Correct the typo to 'session' and replace 'tmp:' with a clear descriptor of the main feature, e.g., 'Add vault and persona integration to session' to accurately convey the changeset's primary objective.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/vault-in-session

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.

@leo-notte
Copy link
Contributor Author

@coderabbitai review

@leo-notte
Copy link
Contributor Author

@greptileai

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 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

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +147 to +157
def _has_persona_tool(self, persona: BasePersona) -> bool:
for tool in self.tools:
if not isinstance(tool, PersonaTool):
continue
try:
if tool.persona.info.persona_id == persona.info.persona_id:
return True
except Exception:
if tool.persona is persona:
return True
return False
Copy link

Choose a reason for hiding this comment

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

Bare except catches all exceptions on line 154, potentially hiding real errors like AttributeError when tool.persona doesn't have info attribute

Suggested change
def _has_persona_tool(self, persona: BasePersona) -> bool:
for tool in self.tools:
if not isinstance(tool, PersonaTool):
continue
try:
if tool.persona.info.persona_id == persona.info.persona_id:
return True
except Exception:
if tool.persona is persona:
return True
return False
def _has_persona_tool(self, persona: BasePersona) -> bool:
for tool in self.tools:
if not isinstance(tool, PersonaTool):
continue
if tool.persona.info.persona_id == persona.info.persona_id:
return True
return False
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/notte-browser/src/notte_browser/session.py
Line: 147:157

Comment:
Bare except catches all exceptions on line 154, potentially hiding real errors like `AttributeError` when `tool.persona` doesn't have `info` attribute

```suggestion
    def _has_persona_tool(self, persona: BasePersona) -> bool:
        for tool in self.tools:
            if not isinstance(tool, PersonaTool):
                continue
            if tool.persona.info.persona_id == persona.info.persona_id:
                return True
        return False
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +56 to +61
if not any(
isinstance(tool, PersonaTool)
and getattr(tool.persona.info, "persona_id", None) == getattr(persona.info, "persona_id", None)
for tool in self.tools
):
self.tools.append(PersonaTool(persona))
Copy link

Choose a reason for hiding this comment

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

Uses getattr with fallback to None for persona_id, but this masks real AttributeError if info exists but has the wrong structure

Suggested change
if not any(
isinstance(tool, PersonaTool)
and getattr(tool.persona.info, "persona_id", None) == getattr(persona.info, "persona_id", None)
for tool in self.tools
):
self.tools.append(PersonaTool(persona))
if not any(
isinstance(tool, PersonaTool) and tool.persona.info.persona_id == persona.info.persona_id
for tool in self.tools
):
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/notte-agent/src/notte_agent/main.py
Line: 56:61

Comment:
Uses `getattr` with fallback to `None` for `persona_id`, but this masks real `AttributeError` if `info` exists but has the wrong structure

```suggestion
            if not any(
                isinstance(tool, PersonaTool) and tool.persona.info.persona_id == persona.info.persona_id
                for tool in self.tools
            ):
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +136 to +138
self.persona: BasePersona | None = persona
if persona is not None:
self.attach_persona(persona)
Copy link

Choose a reason for hiding this comment

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

Check that vault from persona is attached - NotteSession doesn't set self.vault = persona.vault when persona has a vault (unlike Agent which does)

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/notte-browser/src/notte_browser/session.py
Line: 136:138

Comment:
Check that vault from persona is attached - `NotteSession` doesn't set `self.vault = persona.vault` when persona has a vault (unlike `Agent` which does)

How can I resolve this? If you propose a fix, please make it concise.

Copy link
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: 3

Caution

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

⚠️ Outside diff range comments (1)
src/notte/__init__.py (1)

7-40: ⚠️ Potential issue | 🟡 Minor

Remove undocumented credential constant re-exports or document their purpose.

The credential constants (EMAIL, USERNAME, PASSWORD, MFA, CARD_NUMBER, CARD_HOLDER_NAME, CARD_EXPIRATION, CARD_CVV) are now exposed at the package root via __all__, but this re-export is neither documented in the README nor used in any code examples. These are test/placeholder values, not production-ready. Either remove these from __all__ or add clear documentation explaining why users should import them directly from notte.

🤖 Fix all issues with AI agents
In `@packages/notte-agent/src/notte_agent/main.py`:
- Around line 56-61: The current de-dup check in the Agent constructor accesses
persona.info and can raise (e.g., _get_info failure), causing Agent creation to
hard-fail; wrap persona.info access in a safe check (try/except) or use
identity-based fallback so failures to fetch info do not raise: in the block
that builds PersonaTool entries (referencing PersonaTool, self.tools, and
persona.info), attempt to read persona.info inside a try and only compare
persona_id when available, otherwise fall back to comparing persona object
identity (or delegate to NotteSession._has_persona_tool if available) before
appending a new PersonaTool(persona).

In `@packages/notte-browser/src/notte_browser/session.py`:
- Around line 135-138: The session currently assigns self.vault from the
explicit vault argument and then attaches persona, so when callers pass persona
but omit vault credential replacement never happens; update the initializer so
that if vault is None and a persona is provided you set self.vault =
persona.vault (or persona.get_vault() if accessor exists) before calling
self.attach_persona(persona), ensuring BasePersona's vault is used as the
session vault and that attach_persona continues to operate against self.vault.

In `@packages/notte-core/src/notte_core/credentials/__init__.py`:
- Around line 1-9: The constants EMAIL, USERNAME, PASSWORD, MFA, CARD_NUMBER,
CARD_HOLDER_NAME, CARD_EXPIRATION and CARD_CVV in notte_core.credentials contain
real-looking PII/secrets; replace their string values with non-sensitive
placeholders (e.g., "EMAIL_PLACEHOLDER", "USERNAME_PLACEHOLDER",
"PASSWORD_PLACEHOLDER", "MFA_PLACEHOLDER", "CARD_NUMBER_PLACEHOLDER",
"CARD_HOLDER_NAME_PLACEHOLDER", "CARD_EXPIRATION_PLACEHOLDER",
"CARD_CVV_PLACEHOLDER") and remove any misleading real-format data; keep them as
clear identifiers so they represent credential types only and do not contain
real or realistic secrets.
🧹 Nitpick comments (2)
packages/notte-core/src/notte_core/credentials/__init__.py (1)

11-20: Sort __all__ to satisfy Ruff (RUF022).

Optional, but this warning will keep surfacing in lint runs.

♻️ Suggested ordering
 __all__ = [
-    "EMAIL",
-    "USERNAME",
-    "PASSWORD",
-    "MFA",
     "CARD_NUMBER",
     "CARD_HOLDER_NAME",
     "CARD_EXPIRATION",
     "CARD_CVV",
+    "EMAIL",
+    "MFA",
+    "PASSWORD",
+    "USERNAME",
 ]
packages/notte-browser/src/notte_browser/session.py (1)

474-491: Avoid re-resolving an already-resolved action just to locate elements.

_action_with_vault() calls self.locate(action), which re-runs NodeResolutionPipe.forward. Since resolved_action already exists, prefer using its selectors directly to avoid extra work and potential drift.

♻️ Suggested refactor
-        locator = await self.locate(action)
+        locator = None
+        if isinstance(action, InteractionAction) and action.selectors is not None:
+            locator = await locate_element(self.window.page, action.selectors)
+        else:
+            locator = await self.locate(action)

Comment on lines +56 to +61
if not any(
isinstance(tool, PersonaTool)
and getattr(tool.persona.info, "persona_id", None) == getattr(persona.info, "persona_id", None)
for tool in self.tools
):
self.tools.append(PersonaTool(persona))
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid hard failure when persona.info lookup fails.

Line 56 now calls persona.info during de-dupe. If _get_info() raises (network, auth, etc.), Agent creation will fail — a new regression. Consider a safe fallback (object identity) like NotteSession._has_persona_tool.

🐛 Suggested hardening
-            if not any(
-                isinstance(tool, PersonaTool)
-                and getattr(tool.persona.info, "persona_id", None) == getattr(persona.info, "persona_id", None)
-                for tool in self.tools
-            ):
+            try:
+                persona_id = getattr(persona.info, "persona_id", None)
+                def _match(tool: BaseTool) -> bool:
+                    return (
+                        isinstance(tool, PersonaTool)
+                        and getattr(tool.persona.info, "persona_id", None) == persona_id
+                    )
+            except Exception:
+                def _match(tool: BaseTool) -> bool:
+                    return isinstance(tool, PersonaTool) and tool.persona is persona
+
+            if not any(_match(tool) for tool in self.tools):
                 self.tools.append(PersonaTool(persona))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not any(
isinstance(tool, PersonaTool)
and getattr(tool.persona.info, "persona_id", None) == getattr(persona.info, "persona_id", None)
for tool in self.tools
):
self.tools.append(PersonaTool(persona))
try:
persona_id = getattr(persona.info, "persona_id", None)
def _match(tool: BaseTool) -> bool:
return (
isinstance(tool, PersonaTool)
and getattr(tool.persona.info, "persona_id", None) == persona_id
)
except Exception:
def _match(tool: BaseTool) -> bool:
return isinstance(tool, PersonaTool) and tool.persona is persona
if not any(_match(tool) for tool in self.tools):
self.tools.append(PersonaTool(persona))
🤖 Prompt for AI Agents
In `@packages/notte-agent/src/notte_agent/main.py` around lines 56 - 61, The
current de-dup check in the Agent constructor accesses persona.info and can
raise (e.g., _get_info failure), causing Agent creation to hard-fail; wrap
persona.info access in a safe check (try/except) or use identity-based fallback
so failures to fetch info do not raise: in the block that builds PersonaTool
entries (referencing PersonaTool, self.tools, and persona.info), attempt to read
persona.info inside a try and only compare persona_id when available, otherwise
fall back to comparing persona object identity (or delegate to
NotteSession._has_persona_tool if available) before appending a new
PersonaTool(persona).

Comment on lines +135 to +138
self.vault: BaseVault | None = vault
self.persona: BasePersona | None = persona
if persona is not None:
self.attach_persona(persona)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Persona-provided vault isn’t wired into the session.

If callers pass persona but omit vault, credential replacement is silently disabled. Consider mirroring Agent behavior by adopting persona.vault when available.

🐛 Suggested fix
         self.vault: BaseVault | None = vault
         self.persona: BasePersona | None = persona
         if persona is not None:
+            if self.vault is None and persona.has_vault:
+                self.vault = persona.vault
             self.attach_persona(persona)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.vault: BaseVault | None = vault
self.persona: BasePersona | None = persona
if persona is not None:
self.attach_persona(persona)
self.vault: BaseVault | None = vault
self.persona: BasePersona | None = persona
if persona is not None:
if self.vault is None and persona.has_vault:
self.vault = persona.vault
self.attach_persona(persona)
🤖 Prompt for AI Agents
In `@packages/notte-browser/src/notte_browser/session.py` around lines 135 - 138,
The session currently assigns self.vault from the explicit vault argument and
then attaches persona, so when callers pass persona but omit vault credential
replacement never happens; update the initializer so that if vault is None and a
persona is provided you set self.vault = persona.vault (or persona.get_vault()
if accessor exists) before calling self.attach_persona(persona), ensuring
BasePersona's vault is used as the session vault and that attach_persona
continues to operate against self.vault.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant