@rtrvr-ai/rover 4.1.0 → 4.2.0

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.
package/dist/index.d.ts CHANGED
@@ -45,6 +45,7 @@ export type RoverInit = {
45
45
  pageConfig?: RoverPageCaptureConfig;
46
46
  allowedDomains?: string[];
47
47
  domainScopeMode?: 'host_only' | 'registrable_domain';
48
+ cloudSandboxEnabled?: boolean;
48
49
  tabPolicy?: {
49
50
  observerByDefault?: boolean;
50
51
  actionLeaseMs?: number;
@@ -1,4 +1,4 @@
1
- import { DEFAULT_AGENT_CARD_PATH, DEFAULT_ROVER_SITE_PATH, createRoverAgentCard, createRoverAgentCardJson, createRoverSiteProfile, createRoverSiteProfileJson, createRoverServiceDescLinkHeader, } from './agentDiscovery.js';
1
+ import { DEFAULT_AGENT_CARD_PATH, DEFAULT_LLMS_PATH, DEFAULT_ROVER_SITE_PATH, createRoverAgentCard, createRoverAgentCardJson, createRoverSiteProfile, createRoverSiteProfileJson, createRoverServiceDescLinkHeader, } from './agentDiscovery.js';
2
2
  const DEFAULT_EMBED_SCRIPT_URL = 'https://rover.rtrvr.ai/embed.js';
3
3
  const DEFAULT_ROVERBOOK_SCRIPT_URL = 'https://rover.rtrvr.ai/roverbook.js';
4
4
  function text(value) {
@@ -260,20 +260,23 @@ function buildRoverBookAttachScript(config, options) {
260
260
  export function createRoverOwnerInstallBundle(input) {
261
261
  const bootConfig = materializeCloudSandboxBootConfig(input.bootConfig);
262
262
  const discoveryConfig = discoveryEnabled(input.discovery) ? input.discovery : null;
263
+ const publishLlmsTxt = llmsEnabled(input, discoveryConfig);
263
264
  const publishedAgentCardUrl = discoveryConfig ? text(discoveryConfig.agentCardUrl) || DEFAULT_AGENT_CARD_PATH : '';
264
265
  const publishedRoverSiteUrl = discoveryConfig ? text(discoveryConfig.roverSiteUrl) || DEFAULT_ROVER_SITE_PATH : '';
265
- const publishLlmsTxt = llmsEnabled(input, discoveryConfig);
266
- const publishedLlmsUrl = discoveryConfig ? text(discoveryConfig.llmsUrl) : '';
266
+ const publishedLlmsUrl = discoveryConfig ? text(discoveryConfig.llmsUrl) || (publishLlmsTxt ? DEFAULT_LLMS_PATH : '') : '';
267
+ const effectiveDiscoveryConfig = discoveryConfig && publishedLlmsUrl && !text(discoveryConfig.llmsUrl)
268
+ ? { ...discoveryConfig, llmsUrl: publishedLlmsUrl }
269
+ : discoveryConfig;
267
270
  const embedScriptUrl = text(input.embedScriptUrl) || DEFAULT_EMBED_SCRIPT_URL;
268
271
  const roverBookEnabled = input.roverBook?.enabled !== false && hasObjectEntries(input.roverBook?.config);
269
272
  const roverBookScriptUrl = roverBookEnabled
270
273
  ? (text(input.roverBook?.scriptUrl) || DEFAULT_ROVERBOOK_SCRIPT_URL)
271
274
  : '';
272
- const agentCard = discoveryConfig ? createRoverAgentCard(discoveryConfig) : undefined;
273
- const agentCardJson = discoveryConfig ? createRoverAgentCardJson(discoveryConfig) : undefined;
274
- const roverSite = discoveryConfig ? createRoverSiteProfile(discoveryConfig) : undefined;
275
- const roverSiteJson = discoveryConfig ? createRoverSiteProfileJson(discoveryConfig) : undefined;
276
- const pageManifestJson = discoveryConfig
275
+ const agentCard = effectiveDiscoveryConfig ? createRoverAgentCard(effectiveDiscoveryConfig) : undefined;
276
+ const agentCardJson = effectiveDiscoveryConfig ? createRoverAgentCardJson(effectiveDiscoveryConfig) : undefined;
277
+ const roverSite = effectiveDiscoveryConfig ? createRoverSiteProfile(effectiveDiscoveryConfig) : undefined;
278
+ const roverSiteJson = effectiveDiscoveryConfig ? createRoverSiteProfileJson(effectiveDiscoveryConfig) : undefined;
279
+ const pageManifestJson = effectiveDiscoveryConfig
277
280
  ? JSON.stringify(agentCard?.extensions?.rover.currentPage || null, null, 2)
278
281
  : undefined;
279
282
  const marker = agentCard && publishedAgentCardUrl
@@ -7,8 +7,24 @@ export type RoverPreviewBootstrapVoiceConfig = {
7
7
  language?: string;
8
8
  autoStopMs?: number;
9
9
  };
10
+ export type RoverPreviewBootstrapExperienceConfig = {
11
+ audio?: {
12
+ narration?: {
13
+ enabled?: boolean;
14
+ defaultMode?: 'guided' | 'always' | 'off';
15
+ rate?: number;
16
+ language?: string;
17
+ voicePreference?: 'auto' | 'system' | 'natural';
18
+ };
19
+ };
20
+ motion?: {
21
+ actionSpotlight?: boolean;
22
+ actionSpotlightColor?: string;
23
+ };
24
+ };
10
25
  export type RoverPreviewBootstrapUiConfig = {
11
26
  voice?: RoverPreviewBootstrapVoiceConfig;
27
+ experience?: RoverPreviewBootstrapExperienceConfig;
12
28
  };
13
29
  export type RoverPreviewBootstrapConfig = {
14
30
  scriptUrl?: string;
@@ -21,10 +37,14 @@ export type RoverPreviewBootstrapConfig = {
21
37
  workerUrl?: string;
22
38
  allowedDomains?: string[];
23
39
  domainScopeMode?: 'host_only' | 'registrable_domain';
40
+ cloudSandboxEnabled?: boolean;
24
41
  sessionScope?: 'shared_site' | 'tab';
25
42
  openOnInit?: boolean;
26
43
  mode?: 'safe' | 'full';
27
44
  allowActions?: boolean;
45
+ pageConfig?: {
46
+ disableAutoScroll?: boolean;
47
+ };
28
48
  ui?: RoverPreviewBootstrapUiConfig;
29
49
  attachLaunch?: RoverPreviewAttachLaunch;
30
50
  };
@@ -2,6 +2,8 @@ const DEFAULT_EMBED_SCRIPT_URL = 'https://rover.rtrvr.ai/embed.js';
2
2
  const DEFAULT_AGENT_BASE = 'https://agent.rtrvr.ai';
3
3
  const VOICE_AUTO_STOP_MIN_MS = 800;
4
4
  const VOICE_AUTO_STOP_MAX_MS = 5000;
5
+ const NARRATION_RATE_MIN = 0.85;
6
+ const NARRATION_RATE_MAX = 1.15;
5
7
  function toStringValue(value) {
6
8
  return String(value || '').trim();
7
9
  }
@@ -41,6 +43,13 @@ function parseIntegerAttr(value) {
41
43
  const parsed = Number(toStringValue(value));
42
44
  return Number.isFinite(parsed) ? Math.trunc(parsed) : undefined;
43
45
  }
46
+ function normalizeHexColor(value) {
47
+ const raw = toStringValue(value);
48
+ if (!raw)
49
+ return undefined;
50
+ const match = raw.match(/^#?([0-9a-fA-F]{6})$/);
51
+ return match ? `#${match[1].toUpperCase()}` : undefined;
52
+ }
44
53
  function normalizeVoiceConfig(value) {
45
54
  if (!value || typeof value !== 'object')
46
55
  return undefined;
@@ -56,6 +65,53 @@ function normalizeVoiceConfig(value) {
56
65
  }
57
66
  return Object.keys(voice).length ? voice : undefined;
58
67
  }
68
+ function normalizeExperienceConfig(value) {
69
+ if (!value || typeof value !== 'object')
70
+ return undefined;
71
+ const experience = {};
72
+ if (value.audio && typeof value.audio === 'object') {
73
+ const narrationInput = value.audio.narration && typeof value.audio.narration === 'object'
74
+ ? value.audio.narration
75
+ : undefined;
76
+ if (narrationInput) {
77
+ const narration = {};
78
+ if (typeof narrationInput.enabled === 'boolean')
79
+ narration.enabled = narrationInput.enabled;
80
+ if (narrationInput.defaultMode === 'guided' ||
81
+ narrationInput.defaultMode === 'always' ||
82
+ narrationInput.defaultMode === 'off') {
83
+ narration.defaultMode = narrationInput.defaultMode;
84
+ }
85
+ const rate = Number(narrationInput.rate);
86
+ if (Number.isFinite(rate)) {
87
+ narration.rate = Math.max(NARRATION_RATE_MIN, Math.min(NARRATION_RATE_MAX, rate));
88
+ }
89
+ const language = toStringValue(narrationInput.language).replace(/[^a-zA-Z0-9-]/g, '').slice(0, 24);
90
+ if (language)
91
+ narration.language = language;
92
+ if (narrationInput.voicePreference === 'auto' ||
93
+ narrationInput.voicePreference === 'system' ||
94
+ narrationInput.voicePreference === 'natural') {
95
+ narration.voicePreference = narrationInput.voicePreference;
96
+ }
97
+ if (Object.keys(narration).length)
98
+ experience.audio = { narration };
99
+ }
100
+ }
101
+ if (value.motion && typeof value.motion === 'object') {
102
+ const motion = {};
103
+ if (typeof value.motion.actionSpotlight === 'boolean') {
104
+ motion.actionSpotlight = value.motion.actionSpotlight;
105
+ }
106
+ const actionSpotlightColor = normalizeHexColor(value.motion.actionSpotlightColor);
107
+ if (actionSpotlightColor) {
108
+ motion.actionSpotlightColor = actionSpotlightColor;
109
+ }
110
+ if (Object.keys(motion).length)
111
+ experience.motion = motion;
112
+ }
113
+ return Object.keys(experience).length ? experience : undefined;
114
+ }
59
115
  function normalizeUiConfig(value) {
60
116
  if (!value || typeof value !== 'object')
61
117
  return undefined;
@@ -63,6 +119,9 @@ function normalizeUiConfig(value) {
63
119
  const voice = normalizeVoiceConfig(value.voice);
64
120
  if (voice)
65
121
  ui.voice = voice;
122
+ const experience = normalizeExperienceConfig(value.experience);
123
+ if (experience)
124
+ ui.experience = experience;
66
125
  return Object.keys(ui).length ? ui : undefined;
67
126
  }
68
127
  function normalizeBootstrapConfig(config) {
@@ -98,6 +157,8 @@ function buildBootstrapPayload(config) {
98
157
  payload.allowedDomains = normalized.allowedDomains;
99
158
  if (normalized.domainScopeMode)
100
159
  payload.domainScopeMode = normalized.domainScopeMode;
160
+ if (typeof normalized.cloudSandboxEnabled === 'boolean')
161
+ payload.cloudSandboxEnabled = normalized.cloudSandboxEnabled;
101
162
  if (normalized.sessionScope)
102
163
  payload.sessionScope = normalized.sessionScope;
103
164
  if (typeof normalized.openOnInit === 'boolean')
@@ -106,8 +167,11 @@ function buildBootstrapPayload(config) {
106
167
  payload.mode = normalized.mode;
107
168
  if (typeof normalized.allowActions === 'boolean')
108
169
  payload.allowActions = normalized.allowActions;
109
- if (normalized.ui?.voice)
110
- payload.ui = { voice: normalized.ui.voice };
170
+ if (typeof normalized.pageConfig?.disableAutoScroll === 'boolean') {
171
+ payload.pageConfig = { disableAutoScroll: normalized.pageConfig.disableAutoScroll };
172
+ }
173
+ if (normalized.ui)
174
+ payload.ui = normalized.ui;
111
175
  return payload;
112
176
  }
113
177
  function buildQueueStub() {
@@ -180,6 +244,8 @@ export function createRoverScriptTagSnippet(config) {
180
244
  attrs.push(`data-allowed-domains="${escapeHtmlAttr(normalized.allowedDomains.join(','))}"`);
181
245
  if (normalized.domainScopeMode)
182
246
  attrs.push(`data-domain-scope-mode="${escapeHtmlAttr(normalized.domainScopeMode)}"`);
247
+ if (typeof normalized.cloudSandboxEnabled === 'boolean')
248
+ attrs.push(`data-cloud-sandbox-enabled="${escapeHtmlAttr(String(normalized.cloudSandboxEnabled))}"`);
183
249
  if (normalized.sessionScope)
184
250
  attrs.push(`data-session-scope="${escapeHtmlAttr(normalized.sessionScope)}"`);
185
251
  if (typeof normalized.openOnInit === 'boolean')
@@ -188,14 +254,34 @@ export function createRoverScriptTagSnippet(config) {
188
254
  attrs.push(`data-mode="${escapeHtmlAttr(normalized.mode)}"`);
189
255
  if (typeof normalized.allowActions === 'boolean')
190
256
  attrs.push(`data-allow-actions="${escapeHtmlAttr(String(normalized.allowActions))}"`);
257
+ if (typeof normalized.pageConfig?.disableAutoScroll === 'boolean') {
258
+ attrs.push(`data-disable-auto-scroll="${escapeHtmlAttr(String(normalized.pageConfig.disableAutoScroll))}"`);
259
+ }
191
260
  if (typeof normalized.ui?.voice?.enabled === 'boolean')
192
261
  attrs.push(`data-voice-enabled="${escapeHtmlAttr(String(normalized.ui.voice.enabled))}"`);
193
262
  if (normalized.ui?.voice?.language)
194
263
  attrs.push(`data-voice-language="${escapeHtmlAttr(normalized.ui.voice.language)}"`);
195
264
  if (typeof normalized.ui?.voice?.autoStopMs === 'number')
196
265
  attrs.push(`data-voice-auto-stop-ms="${escapeHtmlAttr(String(normalized.ui.voice.autoStopMs))}"`);
266
+ const narration = normalized.ui?.experience?.audio?.narration;
267
+ if (typeof narration?.enabled === 'boolean')
268
+ attrs.push(`data-narration-enabled="${escapeHtmlAttr(String(narration.enabled))}"`);
269
+ if (narration?.defaultMode)
270
+ attrs.push(`data-narration-default-mode="${escapeHtmlAttr(narration.defaultMode)}"`);
271
+ if (typeof narration?.rate === 'number')
272
+ attrs.push(`data-narration-rate="${escapeHtmlAttr(String(narration.rate))}"`);
273
+ if (narration?.language)
274
+ attrs.push(`data-narration-language="${escapeHtmlAttr(narration.language)}"`);
275
+ if (narration?.voicePreference)
276
+ attrs.push(`data-narration-voice-preference="${escapeHtmlAttr(narration.voicePreference)}"`);
277
+ if (typeof normalized.ui?.experience?.motion?.actionSpotlight === 'boolean') {
278
+ attrs.push(`data-action-spotlight="${escapeHtmlAttr(String(normalized.ui.experience.motion.actionSpotlight))}"`);
279
+ }
280
+ if (normalized.ui?.experience?.motion?.actionSpotlightColor) {
281
+ attrs.push(`data-action-spotlight-color="${escapeHtmlAttr(normalized.ui.experience.motion.actionSpotlightColor)}"`);
282
+ }
197
283
  const runEndpoint = `${toStringValue(normalized.apiBase) || DEFAULT_AGENT_BASE}/v1/a2w/runs`;
198
- const markerJson = escapeScriptJson(JSON.stringify({ a2w: runEndpoint, run: runEndpoint, task: runEndpoint }));
284
+ const markerJson = escapeScriptJson(JSON.stringify({ a2w: runEndpoint, run: runEndpoint }));
199
285
  return [
200
286
  `<script type="application/agent+json" data-rover-agent-discovery="marker">${markerJson}</script>`,
201
287
  '<link rel="service-desc" href="/.well-known/agent-card.json" type="application/json" data-rover-agent-discovery="service-desc" />',
@@ -235,6 +321,9 @@ export function readRoverScriptDataAttributes(scriptEl) {
235
321
  if (domainScopeMode === 'host_only' || domainScopeMode === 'registrable_domain') {
236
322
  config.domainScopeMode = domainScopeMode;
237
323
  }
324
+ const cloudSandboxEnabled = parseBooleanAttr(scriptEl.getAttribute('data-cloud-sandbox-enabled'));
325
+ if (typeof cloudSandboxEnabled === 'boolean')
326
+ config.cloudSandboxEnabled = cloudSandboxEnabled;
238
327
  const sessionScope = toStringValue(scriptEl.getAttribute('data-session-scope'));
239
328
  if (sessionScope === 'shared_site' || sessionScope === 'tab') {
240
329
  config.sessionScope = sessionScope;
@@ -249,16 +338,50 @@ export function readRoverScriptDataAttributes(scriptEl) {
249
338
  const allowActions = parseBooleanAttr(scriptEl.getAttribute('data-allow-actions'));
250
339
  if (typeof allowActions === 'boolean')
251
340
  config.allowActions = allowActions;
341
+ const disableAutoScroll = parseBooleanAttr(scriptEl.getAttribute('data-disable-auto-scroll'));
342
+ if (typeof disableAutoScroll === 'boolean')
343
+ config.pageConfig = { disableAutoScroll };
252
344
  const voiceEnabled = parseBooleanAttr(scriptEl.getAttribute('data-voice-enabled'));
253
345
  const voiceLanguage = toStringValue(scriptEl.getAttribute('data-voice-language'));
254
346
  const voiceAutoStopMs = parseIntegerAttr(scriptEl.getAttribute('data-voice-auto-stop-ms'));
255
- if (typeof voiceEnabled === 'boolean' || voiceLanguage || typeof voiceAutoStopMs === 'number') {
347
+ const narrationEnabled = parseBooleanAttr(scriptEl.getAttribute('data-narration-enabled'));
348
+ const narrationDefaultMode = toStringValue(scriptEl.getAttribute('data-narration-default-mode'));
349
+ const narrationRate = Number(toStringValue(scriptEl.getAttribute('data-narration-rate')));
350
+ const narrationLanguage = toStringValue(scriptEl.getAttribute('data-narration-language'));
351
+ const narrationVoicePreference = toStringValue(scriptEl.getAttribute('data-narration-voice-preference'));
352
+ const actionSpotlight = parseBooleanAttr(scriptEl.getAttribute('data-action-spotlight'));
353
+ const actionSpotlightColor = normalizeHexColor(scriptEl.getAttribute('data-action-spotlight-color'));
354
+ const voice = normalizeVoiceConfig({
355
+ ...(typeof voiceEnabled === 'boolean' ? { enabled: voiceEnabled } : {}),
356
+ ...(voiceLanguage ? { language: voiceLanguage } : {}),
357
+ ...(typeof voiceAutoStopMs === 'number' ? { autoStopMs: voiceAutoStopMs } : {}),
358
+ });
359
+ const experience = normalizeExperienceConfig({
360
+ ...(typeof narrationEnabled === 'boolean' || narrationDefaultMode || Number.isFinite(narrationRate) || narrationLanguage || narrationVoicePreference
361
+ ? {
362
+ audio: {
363
+ narration: {
364
+ ...(typeof narrationEnabled === 'boolean' ? { enabled: narrationEnabled } : {}),
365
+ ...(narrationDefaultMode === 'guided' || narrationDefaultMode === 'always' || narrationDefaultMode === 'off'
366
+ ? { defaultMode: narrationDefaultMode }
367
+ : {}),
368
+ ...(Number.isFinite(narrationRate) ? { rate: narrationRate } : {}),
369
+ ...(narrationLanguage ? { language: narrationLanguage } : {}),
370
+ ...(narrationVoicePreference === 'auto' || narrationVoicePreference === 'system' || narrationVoicePreference === 'natural'
371
+ ? { voicePreference: narrationVoicePreference }
372
+ : {}),
373
+ },
374
+ },
375
+ }
376
+ : {}),
377
+ ...(typeof actionSpotlight === 'boolean' || actionSpotlightColor
378
+ ? { motion: { ...(typeof actionSpotlight === 'boolean' ? { actionSpotlight } : {}), ...(actionSpotlightColor ? { actionSpotlightColor } : {}) } }
379
+ : {}),
380
+ });
381
+ if (voice || experience) {
256
382
  config.ui = {
257
- voice: {
258
- ...(typeof voiceEnabled === 'boolean' ? { enabled: voiceEnabled } : {}),
259
- ...(voiceLanguage ? { language: voiceLanguage } : {}),
260
- ...(typeof voiceAutoStopMs === 'number' ? { autoStopMs: voiceAutoStopMs } : {}),
261
- },
383
+ ...(voice ? { voice } : {}),
384
+ ...(experience ? { experience } : {}),
262
385
  };
263
386
  }
264
387
  return config;