ai-browser 0.2.2 → 0.2.4

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.
@@ -0,0 +1,126 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Task Submit - AI Browser</title>
7
+ <style>
8
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 0; background: #0d1117; color: #c9d1d9; }
9
+ .wrap { max-width: 900px; margin: 24px auto; padding: 0 16px; }
10
+ h1 { font-size: 24px; margin-bottom: 16px; }
11
+ .card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; margin-bottom: 16px; }
12
+ label { display: block; margin: 12px 0 6px; color: #8b949e; font-size: 13px; }
13
+ input, textarea { width: 100%; box-sizing: border-box; padding: 10px; border-radius: 6px; border: 1px solid #30363d; background: #0d1117; color: #c9d1d9; font-size: 14px; }
14
+ textarea { min-height: 90px; resize: vertical; }
15
+ .row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
16
+ button { margin-top: 16px; background: #238636; color: #fff; border: none; border-radius: 6px; padding: 10px 16px; cursor: pointer; font-weight: 600; }
17
+ button:disabled { opacity: 0.6; cursor: not-allowed; }
18
+ .tip { color: #8b949e; font-size: 12px; margin-top: 8px; }
19
+ .error { color: #ff7b72; white-space: pre-wrap; }
20
+ </style>
21
+ </head>
22
+ <body>
23
+ <div class="wrap">
24
+ <h1>Task Submit</h1>
25
+ <div class="card">
26
+ <label for="goal">Goal</label>
27
+ <input id="goal" type="text" value="批量提取页面信息">
28
+
29
+ <label for="urls">URLs (one per line)</label>
30
+ <textarea id="urls">https://example.com</textarea>
31
+
32
+ <div class="row">
33
+ <div>
34
+ <label for="maxDurationMs">maxDurationMs</label>
35
+ <input id="maxDurationMs" type="number" value="30000" min="1000">
36
+ </div>
37
+ <div>
38
+ <label for="maxSteps">maxSteps</label>
39
+ <input id="maxSteps" type="number" value="20" min="1">
40
+ </div>
41
+ </div>
42
+
43
+ <div class="row">
44
+ <div>
45
+ <label for="maxRetries">maxRetries</label>
46
+ <input id="maxRetries" type="number" value="1" min="0">
47
+ </div>
48
+ <div>
49
+ <label for="maxToolCalls">maxToolCalls</label>
50
+ <input id="maxToolCalls" type="number" value="120" min="1">
51
+ </div>
52
+ </div>
53
+
54
+ <label for="outputSchema">outputSchema (optional JSON)</label>
55
+ <textarea id="outputSchema">{
56
+ "type": "object",
57
+ "properties": {
58
+ "items": { "type": "array" }
59
+ }
60
+ }</textarea>
61
+
62
+ <button id="submitBtn">Submit Task</button>
63
+ <div class="tip">On success you will be redirected to the task result page.</div>
64
+ <div id="error" class="error"></div>
65
+ </div>
66
+ </div>
67
+
68
+ <script>
69
+ const submitBtn = document.getElementById('submitBtn');
70
+ const errorEl = document.getElementById('error');
71
+
72
+ function parseOptionalJson(text) {
73
+ const trimmed = text.trim();
74
+ if (!trimmed) return undefined;
75
+ try {
76
+ return JSON.parse(trimmed);
77
+ } catch {
78
+ throw new Error('outputSchema JSON format is invalid.');
79
+ }
80
+ }
81
+
82
+ submitBtn.addEventListener('click', async () => {
83
+ submitBtn.disabled = true;
84
+ errorEl.textContent = '';
85
+
86
+ try {
87
+ const urls = document.getElementById('urls').value
88
+ .split('\n')
89
+ .map((s) => s.trim())
90
+ .filter(Boolean);
91
+
92
+ const payload = {
93
+ goal: document.getElementById('goal').value.trim(),
94
+ inputs: urls.length > 0 ? { urls } : {},
95
+ constraints: {
96
+ maxDurationMs: Number(document.getElementById('maxDurationMs').value),
97
+ maxSteps: Number(document.getElementById('maxSteps').value),
98
+ },
99
+ budget: {
100
+ maxRetries: Number(document.getElementById('maxRetries').value),
101
+ maxToolCalls: Number(document.getElementById('maxToolCalls').value),
102
+ },
103
+ outputSchema: parseOptionalJson(document.getElementById('outputSchema').value),
104
+ };
105
+
106
+ const resp = await fetch('/v1/tasks', {
107
+ method: 'POST',
108
+ headers: { 'content-type': 'application/json' },
109
+ body: JSON.stringify(payload),
110
+ });
111
+
112
+ const data = await resp.json();
113
+ if (!resp.ok) {
114
+ throw new Error(JSON.stringify(data, null, 2));
115
+ }
116
+
117
+ window.location.href = `/task-result.html?taskId=${encodeURIComponent(data.taskId)}`;
118
+ } catch (err) {
119
+ errorEl.textContent = err.message || String(err);
120
+ } finally {
121
+ submitBtn.disabled = false;
122
+ }
123
+ });
124
+ </script>
125
+ </body>
126
+ </html>