Skip to content

Commit 1797e6e

Browse files
authored
Merge pull request #214 from Predicate-Labs/rebrand_params
Canonical predicate* params
2 parents 9de186f + d79be3b commit 1797e6e

File tree

7 files changed

+99
-28
lines changed

7 files changed

+99
-28
lines changed

predicate/agent_runtime.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def __init__(
125125
backend: BrowserBackend,
126126
tracer: Tracer,
127127
snapshot_options: SnapshotOptions | None = None,
128+
predicate_api_key: str | None = None,
128129
sentience_api_key: str | None = None,
129130
tool_registry: ToolRegistry | None = None,
130131
):
@@ -138,7 +139,8 @@ def __init__(
138139
- PlaywrightBackend (future, for direct Playwright)
139140
tracer: Tracer for emitting verification events
140141
snapshot_options: Default options for snapshots
141-
sentience_api_key: API key for Pro/Enterprise tier (enables Gateway refinement)
142+
predicate_api_key: Canonical API key parameter for Pro/Enterprise tier.
143+
sentience_api_key: Backward-compatible API key alias (legacy name).
142144
tool_registry: Optional ToolRegistry for LLM-callable tools
143145
"""
144146
self.backend = backend
@@ -147,8 +149,10 @@ def __init__(
147149

148150
# Build default snapshot options with API key if provided
149151
default_opts = snapshot_options or SnapshotOptions()
150-
if sentience_api_key:
151-
default_opts.sentience_api_key = sentience_api_key
152+
effective_api_key = predicate_api_key or sentience_api_key
153+
if effective_api_key:
154+
default_opts.predicate_api_key = effective_api_key
155+
default_opts.sentience_api_key = effective_api_key
152156
if default_opts.use_api is None:
153157
default_opts.use_api = True
154158
self._snapshot_options = default_opts
@@ -193,6 +197,7 @@ def from_playwright_page(
193197
page: Page,
194198
tracer: Tracer,
195199
snapshot_options: SnapshotOptions | None = None,
200+
predicate_api_key: str | None = None,
196201
sentience_api_key: str | None = None,
197202
tool_registry: ToolRegistry | None = None,
198203
) -> AgentRuntime:
@@ -203,7 +208,8 @@ def from_playwright_page(
203208
page: Playwright Page for browser interaction
204209
tracer: Tracer for emitting verification events
205210
snapshot_options: Default options for snapshots
206-
sentience_api_key: API key for Pro/Enterprise tier
211+
predicate_api_key: Canonical API key parameter for Pro/Enterprise tier.
212+
sentience_api_key: Backward-compatible API key alias (legacy name).
207213
tool_registry: Optional ToolRegistry for LLM-callable tools
208214
209215
Returns:
@@ -216,6 +222,7 @@ def from_playwright_page(
216222
backend=backend,
217223
tracer=tracer,
218224
snapshot_options=snapshot_options,
225+
predicate_api_key=predicate_api_key,
219226
sentience_api_key=sentience_api_key,
220227
tool_registry=tool_registry,
221228
)
@@ -226,6 +233,7 @@ def attach(
226233
page: Page,
227234
tracer: Tracer,
228235
snapshot_options: SnapshotOptions | None = None,
236+
predicate_api_key: str | None = None,
229237
sentience_api_key: str | None = None,
230238
tool_registry: ToolRegistry | None = None,
231239
) -> AgentRuntime:
@@ -236,6 +244,7 @@ def attach(
236244
page=page,
237245
tracer=tracer,
238246
snapshot_options=snapshot_options,
247+
predicate_api_key=predicate_api_key,
239248
sentience_api_key=sentience_api_key,
240249
tool_registry=tool_registry,
241250
)
@@ -247,6 +256,7 @@ async def from_sentience_browser(
247256
page: Page,
248257
tracer: Tracer,
249258
snapshot_options: SnapshotOptions | None = None,
259+
predicate_api_key: str | None = None,
250260
sentience_api_key: str | None = None,
251261
) -> AgentRuntime:
252262
"""
@@ -260,7 +270,8 @@ async def from_sentience_browser(
260270
page: Playwright Page for browser interaction
261271
tracer: Tracer for emitting verification events
262272
snapshot_options: Default options for snapshots
263-
sentience_api_key: API key for Pro/Enterprise tier
273+
predicate_api_key: Canonical API key parameter for Pro/Enterprise tier.
274+
sentience_api_key: Backward-compatible API key alias (legacy name).
264275
265276
Returns:
266277
AgentRuntime instance
@@ -272,6 +283,7 @@ async def from_sentience_browser(
272283
backend=backend,
273284
tracer=tracer,
274285
snapshot_options=snapshot_options,
286+
predicate_api_key=predicate_api_key,
275287
sentience_api_key=sentience_api_key,
276288
)
277289
# Store browser reference for snapshot() to use

predicate/backends/sentience_context.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class SentienceContext:
8686
def __init__(
8787
self,
8888
*,
89+
predicate_api_key: str | None = None,
8990
sentience_api_key: str | None = None,
9091
use_api: bool | None = None,
9192
max_elements: int = 60,
@@ -96,13 +97,14 @@ def __init__(
9697
Initialize SentienceContext.
9798
9899
Args:
99-
sentience_api_key: Sentience API key for gateway mode
100+
predicate_api_key: Canonical API key parameter for gateway mode.
101+
sentience_api_key: Backward-compatible API key alias (legacy name).
100102
use_api: Force API vs extension mode (auto-detected if None)
101103
max_elements: Maximum elements to fetch from snapshot
102104
show_overlay: Show visual overlay highlighting elements in browser
103105
top_element_selector: Configuration for element selection strategy
104106
"""
105-
self._api_key = sentience_api_key
107+
self._api_key = predicate_api_key or sentience_api_key
106108
self._use_api = use_api
107109
self._max_elements = max_elements
108110
self._show_overlay = show_overlay
@@ -155,7 +157,7 @@ async def build(
155157

156158
# Set API options
157159
if self._api_key:
158-
options.sentience_api_key = self._api_key
160+
options.predicate_api_key = self._api_key
159161
if self._use_api is not None:
160162
options.use_api = self._use_api
161163
elif self._api_key:

predicate/backends/snapshot.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,10 @@ async def snapshot(
247247

248248
# Determine if we should use server-side API
249249
# Same logic as main snapshot() function in predicate/snapshot.py
250-
should_use_api = (
251-
options.use_api if options.use_api is not None else (options.sentience_api_key is not None)
252-
)
250+
effective_api_key = options.predicate_api_key or options.sentience_api_key
251+
should_use_api = options.use_api if options.use_api is not None else (effective_api_key is not None)
253252

254-
if should_use_api and options.sentience_api_key:
253+
if should_use_api and effective_api_key:
255254
# Use server-side API (Pro/Enterprise tier)
256255
return await _snapshot_via_api(backend, options)
257256
else:
@@ -596,7 +595,7 @@ async def _snapshot_via_api(
596595
try:
597596
api_result = await _post_snapshot_to_gateway_async(
598597
payload,
599-
options.sentience_api_key,
598+
options.predicate_api_key or options.sentience_api_key,
600599
api_url,
601600
timeout_s=options.gateway_timeout_s,
602601
)

predicate/debugger.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,22 @@ def attach(
4848
page: Page,
4949
tracer: Tracer,
5050
snapshot_options: SnapshotOptions | None = None,
51+
predicate_api_key: str | None = None,
5152
sentience_api_key: str | None = None,
5253
tool_registry: ToolRegistry | None = None,
5354
) -> SentienceDebugger:
54-
runtime = AgentRuntime.from_playwright_page(
55-
page=page,
56-
tracer=tracer,
57-
snapshot_options=snapshot_options,
58-
sentience_api_key=sentience_api_key,
59-
tool_registry=tool_registry,
60-
)
55+
factory_kwargs: dict[str, Any] = {
56+
"page": page,
57+
"tracer": tracer,
58+
"snapshot_options": snapshot_options,
59+
"sentience_api_key": sentience_api_key,
60+
"tool_registry": tool_registry,
61+
}
62+
# Preserve old call shape unless new parameter is explicitly used.
63+
if predicate_api_key is not None:
64+
factory_kwargs["predicate_api_key"] = predicate_api_key
65+
66+
runtime = AgentRuntime.from_playwright_page(**factory_kwargs)
6167
return cls(runtime=runtime)
6268

6369
def begin_step(self, goal: str, step_index: int | None = None) -> str:

predicate/models.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from dataclasses import dataclass
88
from typing import Any, Literal
99

10-
from pydantic import BaseModel, ConfigDict, Field
10+
from pydantic import BaseModel, ConfigDict, Field, model_validator
1111

1212

1313
class BBox(BaseModel):
@@ -787,10 +787,24 @@ class SnapshotOptions(BaseModel):
787787
)
788788

789789
# API credentials (for browser-use integration without SentienceBrowser)
790-
sentience_api_key: str | None = None # Sentience API key for Pro/Enterprise features
790+
# Keep both names during migration; Predicate name is canonical.
791+
predicate_api_key: str | None = None
792+
sentience_api_key: str | None = None
791793

792794
model_config = ConfigDict(arbitrary_types_allowed=True)
793795

796+
@model_validator(mode="after")
797+
def _sync_api_key_aliases(self) -> "SnapshotOptions":
798+
"""
799+
Keep predicate_api_key and sentience_api_key in sync during migration.
800+
Predicate naming wins when both are set.
801+
"""
802+
if self.predicate_api_key:
803+
self.sentience_api_key = self.predicate_api_key
804+
elif self.sentience_api_key:
805+
self.predicate_api_key = self.sentience_api_key
806+
return self
807+
794808

795809
class AgentActionResult(BaseModel):
796810
"""Result of a single agent action (from agent.act())"""

predicate/snapshot.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,9 @@ def snapshot(
476476
if options is None:
477477
options = SnapshotOptions()
478478

479-
# Resolve API key: options.sentience_api_key takes precedence, then browser.api_key
480-
# This allows browser-use users to pass api_key via options without SentienceBrowser
481-
effective_api_key = options.sentience_api_key or browser.api_key
479+
# Resolve API key: predicate_api_key is canonical, sentience_api_key kept for compatibility.
480+
# This allows browser-use users to pass api_key via options without SentienceBrowser.
481+
effective_api_key = options.predicate_api_key or options.sentience_api_key or browser.api_key
482482

483483
# Determine if we should use server-side API
484484
should_use_api = (
@@ -710,9 +710,9 @@ async def snapshot_async(
710710
if options is None:
711711
options = SnapshotOptions()
712712

713-
# Resolve API key: options.sentience_api_key takes precedence, then browser.api_key
714-
# This allows browser-use users to pass api_key via options without SentienceBrowser
715-
effective_api_key = options.sentience_api_key or browser.api_key
713+
# Resolve API key: predicate_api_key is canonical, sentience_api_key kept for compatibility.
714+
# This allows browser-use users to pass api_key via options without SentienceBrowser.
715+
effective_api_key = options.predicate_api_key or options.sentience_api_key or browser.api_key
716716

717717
# Determine if we should use server-side API
718718
should_use_api = (
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# pylint: disable=protected-access
2+
from unittest.mock import MagicMock
3+
4+
from predicate.agent_runtime import AgentRuntime
5+
from predicate.models import SnapshotOptions
6+
7+
8+
def test_snapshot_options_accepts_predicate_api_key() -> None:
9+
opts = SnapshotOptions(predicate_api_key="pk_test")
10+
assert opts.predicate_api_key == "pk_test"
11+
assert opts.sentience_api_key == "pk_test"
12+
13+
14+
def test_snapshot_options_keeps_backward_compatible_sentience_api_key() -> None:
15+
opts = SnapshotOptions(sentience_api_key="sk_test")
16+
assert opts.sentience_api_key == "sk_test"
17+
assert opts.predicate_api_key == "sk_test"
18+
19+
20+
def test_agent_runtime_accepts_predicate_api_key() -> None:
21+
runtime = AgentRuntime(
22+
backend=MagicMock(),
23+
tracer=MagicMock(),
24+
predicate_api_key="pk_runtime",
25+
)
26+
assert runtime._snapshot_options.predicate_api_key == "pk_runtime"
27+
assert runtime._snapshot_options.sentience_api_key == "pk_runtime"
28+
29+
30+
def test_agent_runtime_prefers_predicate_api_key_when_both_provided() -> None:
31+
runtime = AgentRuntime(
32+
backend=MagicMock(),
33+
tracer=MagicMock(),
34+
predicate_api_key="pk_new",
35+
sentience_api_key="sk_old",
36+
)
37+
assert runtime._snapshot_options.predicate_api_key == "pk_new"
38+
assert runtime._snapshot_options.sentience_api_key == "pk_new"

0 commit comments

Comments
 (0)