@mobileai/react-native 0.9.25 → 0.9.27

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.
@@ -5,8 +5,9 @@
5
5
  *
6
6
  * Strategies (in priority order):
7
7
  * 1. Switch → onValueChange (toggle)
8
- * 2. Direct onPress on element
9
- * 3. Bubble up fiber tree to find parent onPress (max 5 levels)
8
+ * 2. Radio onPress / onValueChange / parent radio-group handler
9
+ * 3. Direct onPress on element
10
+ * 4. Bubble up fiber tree to find parent onPress (max 5 levels)
10
11
  *
11
12
  * Includes Maestro-style tap verification:
12
13
  * - Captures element count + screen name before tap
@@ -16,10 +17,43 @@
16
17
  import { walkFiberTree } from "../core/FiberTreeWalker.js";
17
18
  import { getParent, getProps } from "../core/FiberAdapter.js";
18
19
  import { dismissAlert } from "../core/NativeAlertInterceptor.js";
20
+ function isScalarSelectionValue(value) {
21
+ return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
22
+ }
23
+ function getRadioSelectionPayload(props) {
24
+ return isScalarSelectionValue(props.value) ? props.value : true;
25
+ }
26
+ function getRadioSelectionHandler(props) {
27
+ if (typeof props.onValueChange === 'function') {
28
+ return {
29
+ channel: 'onValueChange',
30
+ handler: props.onValueChange
31
+ };
32
+ }
33
+ if (typeof props.onCheckedChange === 'function') {
34
+ return {
35
+ channel: 'onCheckedChange',
36
+ handler: props.onCheckedChange
37
+ };
38
+ }
39
+ if (typeof props.onChange === 'function') {
40
+ return {
41
+ channel: 'onChange',
42
+ handler: props.onChange
43
+ };
44
+ }
45
+ if (typeof props.onSelect === 'function') {
46
+ return {
47
+ channel: 'onSelect',
48
+ handler: props.onSelect
49
+ };
50
+ }
51
+ return null;
52
+ }
19
53
  export function createTapTool(context) {
20
54
  return {
21
55
  name: 'tap',
22
- description: 'Tap an interactive element by its index. Works universally on buttons, switches, and custom components.',
56
+ description: 'Tap an interactive element by its index. Works universally on buttons, radios, switches, and custom components.',
23
57
  parameters: {
24
58
  index: {
25
59
  type: 'number',
@@ -57,7 +91,31 @@ export function createTapTool(context) {
57
91
  }
58
92
  }
59
93
 
60
- // Strategy 2: Direct onPress
94
+ // Strategy 2: Radio → own selection handler
95
+ if (element.type === 'radio') {
96
+ const radioPayload = getRadioSelectionPayload(element.props);
97
+ const ownSelectionHandler = getRadioSelectionHandler(element.props);
98
+ if (element.props.onPress) {
99
+ try {
100
+ element.props.onPress();
101
+ await new Promise(resolve => setTimeout(resolve, 500));
102
+ return `✅ Selected [${args.index}] "${element.label}"`;
103
+ } catch (error) {
104
+ return `❌ Error selecting [${args.index}]: ${error.message}`;
105
+ }
106
+ }
107
+ if (ownSelectionHandler) {
108
+ try {
109
+ ownSelectionHandler.handler(radioPayload);
110
+ await new Promise(resolve => setTimeout(resolve, 500));
111
+ return `✅ Selected [${args.index}] "${element.label}"`;
112
+ } catch (error) {
113
+ return `❌ Error selecting [${args.index}]: ${error.message}`;
114
+ }
115
+ }
116
+ }
117
+
118
+ // Strategy 3: Direct onPress
61
119
  if (element.props.onPress) {
62
120
  try {
63
121
  element.props.onPress();
@@ -81,9 +139,10 @@ export function createTapTool(context) {
81
139
  }
82
140
  }
83
141
 
84
- // Strategy 3: Bubble up fiber tree (like RNTL's findEventHandler)
142
+ // Strategy 4: Bubble up fiber tree (like RNTL's findEventHandler)
85
143
  let fiber = getParent(element.fiberNode);
86
144
  let bubbleDepth = 0;
145
+ const radioPayload = element.type === 'radio' ? getRadioSelectionPayload(element.props) : undefined;
87
146
  while (fiber && bubbleDepth < 5) {
88
147
  const parentProps = getProps(fiber);
89
148
  if (parentProps.onPress && typeof parentProps.onPress === 'function') {
@@ -95,10 +154,22 @@ export function createTapTool(context) {
95
154
  return `❌ Error tapping parent of [${args.index}]: ${error.message}`;
96
155
  }
97
156
  }
157
+ if (element.type === 'radio') {
158
+ const parentSelectionHandler = getRadioSelectionHandler(parentProps);
159
+ if (parentSelectionHandler) {
160
+ try {
161
+ parentSelectionHandler.handler(radioPayload);
162
+ await new Promise(resolve => setTimeout(resolve, 500));
163
+ return `✅ Selected [${args.index}] "${element.label}" via parent group`;
164
+ } catch (error) {
165
+ return `❌ Error selecting [${args.index}] via parent group: ${error.message}`;
166
+ }
167
+ }
168
+ }
98
169
  fiber = getParent(fiber);
99
170
  bubbleDepth++;
100
171
  }
101
- return `❌ Element [${args.index}] "${element.label}" has no tap handler (no onPress or onValueChange found).`;
172
+ return `❌ Element [${args.index}] "${element.label}" has no tap handler (no onPress, onValueChange, or radio selection handler found).`;
102
173
  }
103
174
  };
104
175
  }
@@ -27,9 +27,16 @@ export declare class AgentRuntime {
27
27
  private lastSuppressedError;
28
28
  private graceTimer;
29
29
  private originalReportErrorsAsExceptions;
30
- private appActionApproved;
30
+ private appActionApprovalScope;
31
+ private appActionApprovalSource;
31
32
  private static readonly APP_ACTION_TOOLS;
32
33
  getConfig(): AgentConfig;
34
+ private resetAppActionApproval;
35
+ private grantWorkflowApproval;
36
+ private hasWorkflowApproval;
37
+ private debugLogChunked;
38
+ private formatInteractiveForDebug;
39
+ private debugScreenSnapshot;
33
40
  constructor(provider: AIProvider, config: AgentConfig, rootRef: any, navRef: any);
34
41
  private registerBuiltInTools;
35
42
  /**
@@ -11,7 +11,7 @@ export type AgentMode = 'text' | 'voice' | 'human';
11
11
  */
12
12
  export type InteractionMode = 'copilot' | 'autopilot';
13
13
  export type AIProviderName = 'gemini' | 'openai';
14
- export type ElementType = 'pressable' | 'text-input' | 'switch' | 'scrollable' | 'slider' | 'picker' | 'date-picker';
14
+ export type ElementType = 'pressable' | 'text-input' | 'switch' | 'radio' | 'scrollable' | 'slider' | 'picker' | 'date-picker';
15
15
  export interface InteractiveElement {
16
16
  /** Unique index assigned during tree walk */
17
17
  index: number;
@@ -33,6 +33,7 @@ export interface InteractiveElement {
33
33
  * - Picker: onValueChange, items, selectedValue
34
34
  * - DatePicker: onChange, onDateChange, mode
35
35
  * - Switch: onValueChange, value
36
+ * - Radio: onPress, onValueChange/onChange, value, checked
36
37
  */
37
38
  props: Record<string, any>;
38
39
  /**
@@ -1,6 +1,6 @@
1
1
  import type { KnowledgeRetriever } from '../core/types';
2
2
  export interface MobileAIKnowledgeRetrieverOptions {
3
- publishableKey: string;
3
+ analyticsKey: string;
4
4
  baseUrl?: string;
5
5
  headers?: Record<string, string>;
6
6
  limit?: number;
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * Strategies (in priority order):
5
5
  * 1. Switch → onValueChange (toggle)
6
- * 2. Direct onPress on element
7
- * 3. Bubble up fiber tree to find parent onPress (max 5 levels)
6
+ * 2. Radio onPress / onValueChange / parent radio-group handler
7
+ * 3. Direct onPress on element
8
+ * 4. Bubble up fiber tree to find parent onPress (max 5 levels)
8
9
  *
9
10
  * Includes Maestro-style tap verification:
10
11
  * - Captures element count + screen name before tap
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=test-tree.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobileai/react-native",
3
- "version": "0.9.25",
3
+ "version": "0.9.27",
4
4
  "description": "Build autonomous AI agents for React Native and Expo apps. Provides AI-native UI traversal, tool calling, and structured reasoning.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",