veil-browser 0.1.2 → 0.1.3

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.
Files changed (2) hide show
  1. package/dist/ai.js +51 -5
  2. package/package.json +1 -1
package/dist/ai.js CHANGED
@@ -124,10 +124,31 @@ Return JSON array of action steps:`;
124
124
  throw new Error(`Ollama error: ${response.status} ${await response.text()}`);
125
125
  const data = await response.json();
126
126
  const content = data.message?.content ?? '';
127
- const jsonMatch = content.match(/\[[\s\S]*\]/);
127
+ let jsonMatch = content.match(/\[[\s\S]*\]/);
128
128
  if (!jsonMatch)
129
129
  throw new Error('Ollama returned no valid JSON array');
130
- return JSON.parse(jsonMatch[0]);
130
+ let jsonStr = jsonMatch[0];
131
+ try {
132
+ return JSON.parse(jsonStr);
133
+ }
134
+ catch {
135
+ jsonStr = jsonStr.replace(/("description":\s*)"([^"]*)"([^"]*?)"([^"]*)"/g, '$1"$2\\\"$3\\\"$4"');
136
+ try {
137
+ return JSON.parse(jsonStr);
138
+ }
139
+ catch {
140
+ const actions = [];
141
+ const blocks = jsonStr.match(/\{\s*"?action"?\s*:\s*"([^"]+)"/g) ?? [];
142
+ blocks.forEach((block) => {
143
+ const actionMatch = block.match(/"action"\s*:\s*"([^"]+)"/);
144
+ if (actionMatch)
145
+ actions.push({ action: actionMatch[1] });
146
+ });
147
+ if (actions.length === 0)
148
+ throw new Error('Could not extract actions from Ollama response');
149
+ return actions;
150
+ }
151
+ }
131
152
  }
132
153
  if (llm.provider === 'openai' || llm.provider === 'openrouter') {
133
154
  const baseUrl = llm.provider === 'openrouter'
@@ -174,11 +195,36 @@ Return JSON array of action steps:`;
174
195
  const content = llm.provider === 'anthropic'
175
196
  ? data.content[0].text
176
197
  : data.choices[0].message.content;
177
- // Extract JSON from response
178
- const jsonMatch = content.match(/\[[\s\S]*\]/);
198
+ // Extract JSON more robustly — handles malformed JSON
199
+ let jsonMatch = content.match(/\[[\s\S]*\]/);
179
200
  if (!jsonMatch)
180
201
  throw new Error('LLM returned no valid JSON array');
181
- return JSON.parse(jsonMatch[0]);
202
+ let jsonStr = jsonMatch[0];
203
+ // Try to parse as-is first
204
+ try {
205
+ return JSON.parse(jsonStr);
206
+ }
207
+ catch {
208
+ // If that fails, try to fix common issues
209
+ // Remove unescaped quotes in description fields
210
+ jsonStr = jsonStr.replace(/("description":\s*)"([^"]*)"([^"]*?)"([^"]*)"/g, '$1"$2\\\"$3\\\"$4"');
211
+ try {
212
+ return JSON.parse(jsonStr);
213
+ }
214
+ catch {
215
+ // Last resort: extract actions manually
216
+ const actions = [];
217
+ const blocks = jsonStr.match(/\{\s*"?action"?\s*:\s*"([^"]+)"/g) ?? [];
218
+ blocks.forEach((block) => {
219
+ const actionMatch = block.match(/"action"\s*:\s*"([^"]+)"/);
220
+ if (actionMatch)
221
+ actions.push({ action: actionMatch[1] });
222
+ });
223
+ if (actions.length === 0)
224
+ throw new Error('Could not extract actions from LLM response');
225
+ return actions;
226
+ }
227
+ }
182
228
  }
183
229
  // Execute a single action step
184
230
  async function executeStep(page, step) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veil-browser",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Stealth browser CLI for AI agents — bypass bot detection, persist sessions, local CAPTCHA solving, MCP server",
5
5
  "keywords": [
6
6
  "browser",