react-native-agentic-ai 0.0.2 → 0.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/LICENSE +20 -0
- package/README.md +253 -14
- package/lib/module/components/AIAgent.js +185 -0
- package/lib/module/components/AIAgent.js.map +1 -0
- package/lib/module/components/AgentChatBar.js +268 -0
- package/lib/module/components/AgentChatBar.js.map +1 -0
- package/lib/module/components/AgentOverlay.js +53 -0
- package/lib/module/components/AgentOverlay.js.map +1 -0
- package/lib/module/core/AgentRuntime.js +640 -0
- package/lib/module/core/AgentRuntime.js.map +1 -0
- package/lib/module/core/FiberTreeWalker.js +362 -0
- package/lib/module/core/FiberTreeWalker.js.map +1 -0
- package/lib/module/core/MCPBridge.js +98 -0
- package/lib/module/core/MCPBridge.js.map +1 -0
- package/lib/module/core/ScreenDehydrator.js +46 -0
- package/lib/module/core/ScreenDehydrator.js.map +1 -0
- package/lib/module/core/systemPrompt.js +164 -0
- package/lib/module/core/systemPrompt.js.map +1 -0
- package/lib/module/core/types.js +2 -0
- package/lib/module/core/types.js.map +1 -0
- package/lib/module/hooks/useAction.js +32 -0
- package/lib/module/hooks/useAction.js.map +1 -0
- package/lib/module/index.js +17 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/providers/GeminiProvider.js +294 -0
- package/lib/module/providers/GeminiProvider.js.map +1 -0
- package/lib/module/utils/logger.js +17 -0
- package/lib/module/utils/logger.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/components/AIAgent.d.ts +65 -0
- package/lib/typescript/src/components/AIAgent.d.ts.map +1 -0
- package/lib/typescript/src/components/AgentChatBar.d.ts +15 -0
- package/lib/typescript/src/components/AgentChatBar.d.ts.map +1 -0
- package/lib/typescript/src/components/AgentOverlay.d.ts +10 -0
- package/lib/typescript/src/components/AgentOverlay.d.ts.map +1 -0
- package/lib/typescript/src/core/AgentRuntime.d.ts +53 -0
- package/lib/typescript/src/core/AgentRuntime.d.ts.map +1 -0
- package/lib/typescript/src/core/FiberTreeWalker.d.ts +31 -0
- package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +1 -0
- package/lib/typescript/src/core/MCPBridge.d.ts +23 -0
- package/lib/typescript/src/core/MCPBridge.d.ts.map +1 -0
- package/lib/typescript/src/core/ScreenDehydrator.d.ts +20 -0
- package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +1 -0
- package/lib/typescript/src/core/systemPrompt.d.ts +9 -0
- package/lib/typescript/src/core/systemPrompt.d.ts.map +1 -0
- package/lib/typescript/src/core/types.d.ts +176 -0
- package/lib/typescript/src/core/types.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useAction.d.ts +13 -0
- package/lib/typescript/src/hooks/useAction.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +10 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/providers/GeminiProvider.d.ts +43 -0
- package/lib/typescript/src/providers/GeminiProvider.d.ts.map +1 -0
- package/lib/typescript/src/utils/logger.d.ts +7 -0
- package/lib/typescript/src/utils/logger.d.ts.map +1 -0
- package/package.json +135 -12
- package/src/components/AIAgent.tsx +262 -0
- package/src/components/AgentChatBar.tsx +258 -0
- package/src/components/AgentOverlay.tsx +48 -0
- package/src/core/AgentRuntime.ts +661 -0
- package/src/core/FiberTreeWalker.ts +404 -0
- package/src/core/MCPBridge.ts +110 -0
- package/src/core/ScreenDehydrator.ts +53 -0
- package/src/core/systemPrompt.ts +162 -0
- package/src/core/types.ts +233 -0
- package/src/hooks/useAction.ts +40 -0
- package/src/index.ts +22 -0
- package/src/providers/GeminiProvider.ts +283 -0
- package/src/utils/logger.ts +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mohamed Salah
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,23 +1,262 @@
|
|
|
1
|
-
# react-native
|
|
1
|
+
# @mobileai/react-native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Also available as **`react-native-agentic-ai`** — same package, same code.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **Autonomous AI agent for React Native** — Your app gets an AI copilot that can see, understand, and interact with your UI. Zero wrappers, zero view rewriting.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/@mobileai/react-native)
|
|
8
|
+
[](https://www.npmjs.com/package/react-native-agentic-ai)
|
|
9
|
+
[](https://github.com/mohamed2m2018/mobileai-react-native/blob/main/LICENSE)
|
|
10
|
+
[]()
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
Wrap your navigation with `<AIAgent>`. The AI automatically understands your entire screen — every button, every input, every label — and acts on it.
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
## ✨ Features
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
- 🤖 **Zero-config UI understanding** — No need to annotate your views. The AI reads your UI automatically.
|
|
17
|
+
- 🧭 **Auto-navigation** — Navigates between screens to complete multi-step tasks.
|
|
18
|
+
- 🔒 **Production-grade security** — Element gating, content masking, lifecycle hooks, human-in-the-loop confirmation.
|
|
19
|
+
- 🧩 **Custom actions** — Expose any business logic (checkout, API calls) as AI-callable tools with `useAction`.
|
|
20
|
+
- 🌐 **MCP bridge** — Let external AI agents (OpenClaw, Claude Desktop) control your app remotely.
|
|
21
|
+
- 🌍 **Bilingual** — English and Arabic support built-in.
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
- 🎯 **Action System** — Built-in + custom actions (navigate, tap, type, scroll)
|
|
17
|
-
- 🤖 **Gemini Integration** — Native function calling support
|
|
18
|
-
- 🔒 **Safety Layer** — Confirmation dialogs, rate limiting, scope control
|
|
19
|
-
- 🌍 **i18n** — English & Arabic support
|
|
23
|
+
## 📦 Installation
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Pick whichever name you prefer — both packages are identical:
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
```bash
|
|
28
|
+
# Scoped name
|
|
29
|
+
npm install @mobileai/react-native
|
|
30
|
+
|
|
31
|
+
# Or the unscoped alias
|
|
32
|
+
npm install react-native-agentic-ai
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
No native modules required. Works with Expo managed workflow out of the box — **no eject needed**.
|
|
36
|
+
|
|
37
|
+
## 🚀 Quick Start
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { AIAgent } from '@mobileai/react-native';
|
|
41
|
+
// or: import { AIAgent } from 'react-native-agentic-ai';
|
|
42
|
+
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
|
|
43
|
+
|
|
44
|
+
export default function App() {
|
|
45
|
+
const navRef = useNavigationContainerRef();
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<AIAgent apiKey="YOUR_GEMINI_API_KEY" navRef={navRef}>
|
|
49
|
+
<NavigationContainer ref={navRef}>
|
|
50
|
+
{/* Your existing screens — zero changes needed */}
|
|
51
|
+
</NavigationContainer>
|
|
52
|
+
</AIAgent>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A floating chat bar appears automatically. Ask the AI to navigate, tap buttons, fill forms — it reads your live UI and acts.
|
|
58
|
+
|
|
59
|
+
## 🔌 API Reference
|
|
60
|
+
|
|
61
|
+
### `<AIAgent>` Component
|
|
62
|
+
|
|
63
|
+
The root provider. Wrap your app once at the top level.
|
|
64
|
+
|
|
65
|
+
| Prop | Type | Default | Description |
|
|
66
|
+
|------|------|---------|-------------|
|
|
67
|
+
| `apiKey` | `string` | — | **Required.** Gemini API key. |
|
|
68
|
+
| `model` | `string` | `'gemini-2.5-flash'` | Gemini model name. |
|
|
69
|
+
| `navRef` | `NavigationContainerRef` | — | Navigation ref for auto-navigation. |
|
|
70
|
+
| `language` | `'en' \| 'ar'` | `'en'` | UI language. |
|
|
71
|
+
| `maxSteps` | `number` | `10` | Max steps per task. |
|
|
72
|
+
| `showChatBar` | `boolean` | `true` | Show the floating chat bar. |
|
|
73
|
+
| `onResult` | `(result) => void` | — | Called when the agent finishes. |
|
|
74
|
+
|
|
75
|
+
### `useAction(name, description, params, handler)`
|
|
76
|
+
|
|
77
|
+
Register a **non-UI action** the AI can call — for business logic that isn't a visible button.
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { useAction } from '@mobileai/react-native';
|
|
81
|
+
// or: import { useAction } from 'react-native-agentic-ai';
|
|
82
|
+
|
|
83
|
+
function CartScreen() {
|
|
84
|
+
const { clearCart, getTotal } = useCart();
|
|
85
|
+
|
|
86
|
+
useAction('checkout', 'Place the order', {}, async () => {
|
|
87
|
+
const total = getTotal();
|
|
88
|
+
clearCart();
|
|
89
|
+
return { success: true, message: `Order placed! Total: $${total}` };
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Param | Type | Description |
|
|
95
|
+
|-------|------|-------------|
|
|
96
|
+
| `name` | `string` | Unique action name. |
|
|
97
|
+
| `description` | `string` | Natural language description for the AI. |
|
|
98
|
+
| `parameters` | `Record<string, string>` | Parameter schema (e.g., `{ itemName: 'string' }`). |
|
|
99
|
+
| `handler` | `(args) => any` | Execution handler. Can be sync or async. |
|
|
100
|
+
|
|
101
|
+
## 🔒 Security
|
|
102
|
+
|
|
103
|
+
### Element Gating
|
|
104
|
+
|
|
105
|
+
Hide specific elements from the AI:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// Per-element: add aiIgnore prop
|
|
109
|
+
<Pressable aiIgnore={true} onPress={handleAdmin}>
|
|
110
|
+
<Text>Admin Panel</Text>
|
|
111
|
+
</Pressable>
|
|
112
|
+
|
|
113
|
+
// Per-ref: blacklist by reference
|
|
114
|
+
const secretRef = useRef(null);
|
|
115
|
+
<AIAgent interactiveBlacklist={[secretRef]}>
|
|
116
|
+
<Pressable ref={secretRef}>Hidden from AI</Pressable>
|
|
117
|
+
</AIAgent>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Content Masking
|
|
121
|
+
|
|
122
|
+
Sanitize sensitive data before the LLM sees it:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<AIAgent
|
|
126
|
+
transformScreenContent={(content) =>
|
|
127
|
+
content.replace(/\b\d{13,16}\b/g, '****-****-****-****')
|
|
128
|
+
}
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Screen-Specific Instructions
|
|
133
|
+
|
|
134
|
+
Guide the AI's behavior on sensitive screens:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<AIAgent
|
|
138
|
+
instructions={{
|
|
139
|
+
system: 'You are a food delivery assistant.',
|
|
140
|
+
getScreenInstructions: (screenName) => {
|
|
141
|
+
if (screenName === 'Cart') {
|
|
142
|
+
return 'Always confirm the total with the user before checkout.';
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
}}
|
|
146
|
+
/>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Human-in-the-Loop
|
|
150
|
+
|
|
151
|
+
Force native confirmation before critical actions:
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
useAction('checkout', 'Place the order', {}, () => {
|
|
155
|
+
return new Promise((resolve) => {
|
|
156
|
+
Alert.alert('Confirm?', 'Place this order?', [
|
|
157
|
+
{ text: 'Cancel', onPress: () => resolve({ success: false }) },
|
|
158
|
+
{ text: 'Yes', onPress: () => resolve({ success: true }) },
|
|
159
|
+
]);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Lifecycle Hooks
|
|
165
|
+
|
|
166
|
+
| Prop | Description |
|
|
167
|
+
|------|-------------|
|
|
168
|
+
| `onBeforeStep` | Called before each agent step. |
|
|
169
|
+
| `onAfterStep` | Called after each step with full history. |
|
|
170
|
+
| `onBeforeTask` | Called before task execution starts. |
|
|
171
|
+
| `onAfterTask` | Called after task completes. |
|
|
172
|
+
|
|
173
|
+
## 🌐 MCP Bridge (Control Your App from Desktop AI)
|
|
174
|
+
|
|
175
|
+
The MCP (Model Context Protocol) bridge lets **external AI agents** — like Claude Desktop, OpenClaw, or any MCP-compatible client — remotely control your React Native app through natural language.
|
|
176
|
+
|
|
177
|
+
### Architecture
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
┌──────────────────┐ SSE/HTTP ┌──────────────────┐ WebSocket ┌──────────────────┐
|
|
181
|
+
│ Claude Desktop │ ◄──────────────► │ MCP Server │ ◄─────────────► │ Your React │
|
|
182
|
+
│ or any MCP │ (port 3100) │ (Node.js) │ (port 3101) │ Native App │
|
|
183
|
+
│ compatible AI │ │ │ │ │
|
|
184
|
+
└──────────────────┘ └──────────────────┘ └──────────────────┘
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### How It Works
|
|
188
|
+
|
|
189
|
+
1. The **MCP server** (included in `mcp-server/`) runs on your machine as a Node.js process
|
|
190
|
+
2. Your **React Native app** connects to the server via WebSocket (`ws://localhost:3101`)
|
|
191
|
+
3. An **external AI** (e.g., Claude Desktop) connects to the MCP server via SSE (`http://localhost:3100/mcp/sse`)
|
|
192
|
+
4. When Claude sends a command like *"Order 2 lemonades"*, the MCP server forwards it to your app
|
|
193
|
+
5. Your app's `AgentRuntime` executes the task autonomously and sends back the result
|
|
194
|
+
|
|
195
|
+
### Setup
|
|
196
|
+
|
|
197
|
+
**1. Start the MCP server:**
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
cd mcp-server
|
|
201
|
+
npm install
|
|
202
|
+
npm start
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
This starts two servers:
|
|
206
|
+
- **HTTP/SSE** on `http://localhost:3100` — for AI clients (Claude, OpenClaw)
|
|
207
|
+
- **WebSocket** on `ws://localhost:3101` — for your React Native app
|
|
208
|
+
|
|
209
|
+
**2. Connect your app:**
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
<AIAgent
|
|
213
|
+
apiKey="YOUR_GEMINI_KEY"
|
|
214
|
+
mcpServerUrl="ws://localhost:3101"
|
|
215
|
+
/>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**3. Connect Claude Desktop** — add this to your Claude config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"mcpServers": {
|
|
223
|
+
"mobile-app": {
|
|
224
|
+
"url": "http://localhost:3100/mcp/sse"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Available MCP Tools
|
|
231
|
+
|
|
232
|
+
| Tool | Description |
|
|
233
|
+
|------|-------------|
|
|
234
|
+
| `execute_task(command)` | Send a natural language task to the app (e.g., *"Add a burger to cart"*) |
|
|
235
|
+
| `get_app_status()` | Check if the React Native app is currently connected |
|
|
236
|
+
|
|
237
|
+
### Environment Variables
|
|
238
|
+
|
|
239
|
+
| Variable | Default | Description |
|
|
240
|
+
|----------|---------|-------------|
|
|
241
|
+
| `MCP_PORT` | `3100` | HTTP/SSE port for AI clients |
|
|
242
|
+
| `WS_PORT` | `3101` | WebSocket port for the React Native app |
|
|
243
|
+
|
|
244
|
+
## 🛠️ Built-in Tools
|
|
245
|
+
|
|
246
|
+
| Tool | Description |
|
|
247
|
+
|------|-------------|
|
|
248
|
+
| `tap(index)` | Tap an interactive element. |
|
|
249
|
+
| `type(index, text)` | Type text into an input. |
|
|
250
|
+
| `navigate(screen)` | Navigate to a screen. |
|
|
251
|
+
| `done(text)` | Complete the task. |
|
|
252
|
+
| `ask_user(question)` | Ask the user for clarification. |
|
|
253
|
+
|
|
254
|
+
## 📋 Requirements
|
|
255
|
+
|
|
256
|
+
- React Native 0.72+
|
|
257
|
+
- Expo SDK 49+ (or bare React Native)
|
|
258
|
+
- Gemini API key — [Get one free](https://aistudio.google.com/apikey)
|
|
259
|
+
|
|
260
|
+
## 📄 License
|
|
261
|
+
|
|
262
|
+
MIT © [Mohamed Salah](https://github.com/mohamed2m2018)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AIAgent — Root provider component for the AI agent.
|
|
5
|
+
*
|
|
6
|
+
* Wraps the app and provides:
|
|
7
|
+
* - Fiber tree root ref for element auto-detection
|
|
8
|
+
* - Navigation ref for auto-navigation
|
|
9
|
+
* - Floating chat bar for user input
|
|
10
|
+
* - Agent runtime context for useAction hooks
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
14
|
+
import { View, StyleSheet } from 'react-native';
|
|
15
|
+
import { AgentRuntime } from "../core/AgentRuntime.js";
|
|
16
|
+
import { GeminiProvider } from "../providers/GeminiProvider.js";
|
|
17
|
+
import { AgentContext } from "../hooks/useAction.js";
|
|
18
|
+
import { AgentChatBar } from "./AgentChatBar.js";
|
|
19
|
+
import { AgentOverlay } from "./AgentOverlay.js";
|
|
20
|
+
import { logger } from "../utils/logger.js";
|
|
21
|
+
import { MCPBridge } from "../core/MCPBridge.js";
|
|
22
|
+
|
|
23
|
+
// ─── Context ───────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
// ─── Props ─────────────────────────────────────────────────────
|
|
26
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
27
|
+
// ─── Component ─────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
export function AIAgent({
|
|
30
|
+
apiKey,
|
|
31
|
+
model = 'gemini-2.5-flash',
|
|
32
|
+
navRef,
|
|
33
|
+
language = 'en',
|
|
34
|
+
maxSteps = 10,
|
|
35
|
+
showChatBar = true,
|
|
36
|
+
children,
|
|
37
|
+
onResult,
|
|
38
|
+
// Security props
|
|
39
|
+
interactiveBlacklist,
|
|
40
|
+
interactiveWhitelist,
|
|
41
|
+
onBeforeStep,
|
|
42
|
+
onAfterStep,
|
|
43
|
+
onBeforeTask,
|
|
44
|
+
onAfterTask,
|
|
45
|
+
transformScreenContent,
|
|
46
|
+
customTools,
|
|
47
|
+
instructions,
|
|
48
|
+
stepDelay,
|
|
49
|
+
mcpServerUrl,
|
|
50
|
+
router,
|
|
51
|
+
pathname
|
|
52
|
+
}) {
|
|
53
|
+
const rootViewRef = useRef(null);
|
|
54
|
+
const [isThinking, setIsThinking] = useState(false);
|
|
55
|
+
const [statusText, setStatusText] = useState('');
|
|
56
|
+
const [lastResult, setLastResult] = useState(null);
|
|
57
|
+
|
|
58
|
+
// Ref-based resolver for ask_user — stays alive across renders
|
|
59
|
+
const askUserResolverRef = useRef(null);
|
|
60
|
+
|
|
61
|
+
// ─── Create Runtime ──────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
const config = useMemo(() => ({
|
|
64
|
+
apiKey,
|
|
65
|
+
model,
|
|
66
|
+
language,
|
|
67
|
+
maxSteps,
|
|
68
|
+
interactiveBlacklist,
|
|
69
|
+
interactiveWhitelist,
|
|
70
|
+
onBeforeStep,
|
|
71
|
+
onAfterStep,
|
|
72
|
+
onBeforeTask,
|
|
73
|
+
onAfterTask,
|
|
74
|
+
transformScreenContent,
|
|
75
|
+
customTools,
|
|
76
|
+
instructions,
|
|
77
|
+
stepDelay,
|
|
78
|
+
mcpServerUrl,
|
|
79
|
+
router,
|
|
80
|
+
pathname,
|
|
81
|
+
onStatusUpdate: setStatusText,
|
|
82
|
+
// Page-agent pattern: block the agent loop until user responds
|
|
83
|
+
onAskUser: question => {
|
|
84
|
+
return new Promise(resolve => {
|
|
85
|
+
askUserResolverRef.current = resolve;
|
|
86
|
+
// Show question in chat bar, allow user input
|
|
87
|
+
setLastResult({
|
|
88
|
+
success: true,
|
|
89
|
+
message: `❓ ${question}`,
|
|
90
|
+
steps: []
|
|
91
|
+
});
|
|
92
|
+
setIsThinking(false);
|
|
93
|
+
setStatusText('');
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}), [apiKey, model, language, maxSteps, interactiveBlacklist, interactiveWhitelist, onBeforeStep, onAfterStep, onBeforeTask, onAfterTask, transformScreenContent, customTools, instructions, stepDelay, mcpServerUrl, router, pathname]);
|
|
97
|
+
const provider = useMemo(() => new GeminiProvider(apiKey, model), [apiKey, model]);
|
|
98
|
+
const runtime = useMemo(() => new AgentRuntime(provider, config, rootViewRef.current, navRef),
|
|
99
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
100
|
+
[provider, config]);
|
|
101
|
+
|
|
102
|
+
// Update refs when they change
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
runtime.updateRefs(rootViewRef.current, navRef);
|
|
105
|
+
}, [runtime, navRef]);
|
|
106
|
+
|
|
107
|
+
// ─── MCP Bridge ──────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (!mcpServerUrl) return;
|
|
111
|
+
logger.info('AIAgent', `Setting up MCP bridge at ${mcpServerUrl}`);
|
|
112
|
+
const bridge = new MCPBridge(mcpServerUrl, runtime);
|
|
113
|
+
return () => {
|
|
114
|
+
bridge.destroy();
|
|
115
|
+
};
|
|
116
|
+
}, [mcpServerUrl, runtime]);
|
|
117
|
+
|
|
118
|
+
// ─── Execute ──────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
const handleSend = useCallback(async message => {
|
|
121
|
+
if (!message.trim()) return;
|
|
122
|
+
logger.info('AIAgent', `User message: "${message}"`);
|
|
123
|
+
|
|
124
|
+
// If there's a pending ask_user, resolve it instead of starting a new execution
|
|
125
|
+
if (askUserResolverRef.current) {
|
|
126
|
+
const resolver = askUserResolverRef.current;
|
|
127
|
+
askUserResolverRef.current = null;
|
|
128
|
+
setIsThinking(true);
|
|
129
|
+
setStatusText('Processing your answer...');
|
|
130
|
+
setLastResult(null);
|
|
131
|
+
resolver(message);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Normal execution — new task
|
|
136
|
+
setIsThinking(true);
|
|
137
|
+
setStatusText('Thinking...');
|
|
138
|
+
setLastResult(null);
|
|
139
|
+
try {
|
|
140
|
+
// Ensure we have the latest Fiber tree ref
|
|
141
|
+
runtime.updateRefs(rootViewRef.current, navRef);
|
|
142
|
+
const result = await runtime.execute(message);
|
|
143
|
+
setLastResult(result);
|
|
144
|
+
onResult?.(result);
|
|
145
|
+
logger.info('AIAgent', `Result: ${result.success ? '✅' : '❌'} ${result.message}`);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
logger.error('AIAgent', 'Execution failed:', error);
|
|
148
|
+
setLastResult({
|
|
149
|
+
success: false,
|
|
150
|
+
message: `Error: ${error.message}`,
|
|
151
|
+
steps: []
|
|
152
|
+
});
|
|
153
|
+
} finally {
|
|
154
|
+
setIsThinking(false);
|
|
155
|
+
setStatusText('');
|
|
156
|
+
}
|
|
157
|
+
}, [runtime, navRef, onResult]);
|
|
158
|
+
|
|
159
|
+
// ─── Render ──────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
return /*#__PURE__*/_jsxs(AgentContext.Provider, {
|
|
162
|
+
value: runtime,
|
|
163
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
164
|
+
ref: rootViewRef,
|
|
165
|
+
style: styles.root,
|
|
166
|
+
collapsable: false,
|
|
167
|
+
children: children
|
|
168
|
+
}), /*#__PURE__*/_jsx(AgentOverlay, {
|
|
169
|
+
visible: isThinking,
|
|
170
|
+
statusText: statusText
|
|
171
|
+
}), showChatBar && /*#__PURE__*/_jsx(AgentChatBar, {
|
|
172
|
+
onSend: handleSend,
|
|
173
|
+
isThinking: isThinking,
|
|
174
|
+
lastResult: lastResult,
|
|
175
|
+
language: language,
|
|
176
|
+
onDismiss: () => setLastResult(null)
|
|
177
|
+
})]
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
const styles = StyleSheet.create({
|
|
181
|
+
root: {
|
|
182
|
+
flex: 1
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=AIAgent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","View","StyleSheet","AgentRuntime","GeminiProvider","AgentContext","AgentChatBar","AgentOverlay","logger","MCPBridge","jsx","_jsx","jsxs","_jsxs","AIAgent","apiKey","model","navRef","language","maxSteps","showChatBar","children","onResult","interactiveBlacklist","interactiveWhitelist","onBeforeStep","onAfterStep","onBeforeTask","onAfterTask","transformScreenContent","customTools","instructions","stepDelay","mcpServerUrl","router","pathname","rootViewRef","isThinking","setIsThinking","statusText","setStatusText","lastResult","setLastResult","askUserResolverRef","config","onStatusUpdate","onAskUser","question","Promise","resolve","current","success","message","steps","provider","runtime","updateRefs","info","bridge","destroy","handleSend","trim","resolver","result","execute","error","Provider","value","ref","style","styles","root","collapsable","visible","onSend","onDismiss","create","flex"],"sourceRoot":"../../../src","sources":["components/AIAgent.tsx"],"mappings":"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","ignoreList":[]}
|