sf-builder-agent 0.8.7 → 0.8.8
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/ai.js +38 -3
- package/dist/ai.js.map +1 -1
- package/package.json +1 -1
- package/src/ai.ts +42 -7
package/dist/ai.js
CHANGED
|
@@ -36,7 +36,8 @@ const SYSTEM_PROMPT = `You are a Salesforce Lightning UI automation agent. You s
|
|
|
36
36
|
- error: Cannot proceed (explain why)
|
|
37
37
|
- ask_user: Ask the human for help (provide clear instructions in "reasoning")
|
|
38
38
|
|
|
39
|
-
## Response Format — JSON only
|
|
39
|
+
## Response Format — STRICT JSON only
|
|
40
|
+
IMPORTANT: Respond with ONLY a JSON object. No explanation, no prose, no markdown. Just the raw JSON object.
|
|
40
41
|
{
|
|
41
42
|
"action": "click|fill|navigate|scroll|keyboard|wait|done|error|ask_user",
|
|
42
43
|
"reasoning": "Brief explanation",
|
|
@@ -114,9 +115,43 @@ export async function decideNextAction(screenshot, objective, actionHistory, pag
|
|
|
114
115
|
}
|
|
115
116
|
const data = await res.json();
|
|
116
117
|
const text = data.choices?.[0]?.message?.content ?? "";
|
|
117
|
-
return
|
|
118
|
+
return parseAIResponse(text);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Extract a JSON decision from the AI response, handling cases where
|
|
122
|
+
* the model wraps JSON in prose or responds with plain text entirely.
|
|
123
|
+
*/
|
|
124
|
+
function parseAIResponse(text) {
|
|
125
|
+
// Strip markdown code fences
|
|
126
|
+
const cleaned = text
|
|
118
127
|
.replace(/```json\n?/g, "")
|
|
119
128
|
.replace(/```/g, "")
|
|
120
|
-
.trim()
|
|
129
|
+
.trim();
|
|
130
|
+
// Try direct parse first (ideal case)
|
|
131
|
+
try {
|
|
132
|
+
return JSON.parse(cleaned);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Not pure JSON — try to extract a JSON object from the text
|
|
136
|
+
}
|
|
137
|
+
// Look for a JSON object embedded in prose: find outermost { ... }
|
|
138
|
+
const start = cleaned.indexOf("{");
|
|
139
|
+
const end = cleaned.lastIndexOf("}");
|
|
140
|
+
if (start !== -1 && end > start) {
|
|
141
|
+
try {
|
|
142
|
+
return JSON.parse(cleaned.slice(start, end + 1));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Malformed JSON block — fall through
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Model responded with pure prose — treat it as a "wait" action
|
|
149
|
+
// so the loop continues instead of crashing
|
|
150
|
+
console.log(` [AI] Non-JSON response, treating as wait: "${cleaned.slice(0, 80)}..."`);
|
|
151
|
+
return {
|
|
152
|
+
action: "wait",
|
|
153
|
+
reasoning: cleaned.slice(0, 200),
|
|
154
|
+
amount: 2000,
|
|
155
|
+
};
|
|
121
156
|
}
|
|
122
157
|
//# sourceMappingURL=ai.js.map
|
package/dist/ai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAyBH,wEAAwE;AAExE,MAAM,cAAc,GAAG,+CAA+C,CAAC;AACvE,MAAM,KAAK,GAAG,6BAA6B,CAAC;AAE5C,kEAAkE;AAClE,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC5E,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACzE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,wEAAwE;AAExE,MAAM,aAAa,GAAG
|
|
1
|
+
{"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/ai.ts
CHANGED
|
@@ -64,7 +64,8 @@ const SYSTEM_PROMPT = `You are a Salesforce Lightning UI automation agent. You s
|
|
|
64
64
|
- error: Cannot proceed (explain why)
|
|
65
65
|
- ask_user: Ask the human for help (provide clear instructions in "reasoning")
|
|
66
66
|
|
|
67
|
-
## Response Format — JSON only
|
|
67
|
+
## Response Format — STRICT JSON only
|
|
68
|
+
IMPORTANT: Respond with ONLY a JSON object. No explanation, no prose, no markdown. Just the raw JSON object.
|
|
68
69
|
{
|
|
69
70
|
"action": "click|fill|navigate|scroll|keyboard|wait|done|error|ask_user",
|
|
70
71
|
"reasoning": "Brief explanation",
|
|
@@ -164,10 +165,44 @@ export async function decideNextAction(
|
|
|
164
165
|
|
|
165
166
|
const text = data.choices?.[0]?.message?.content ?? "";
|
|
166
167
|
|
|
167
|
-
return
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
return parseAIResponse(text);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Extract a JSON decision from the AI response, handling cases where
|
|
173
|
+
* the model wraps JSON in prose or responds with plain text entirely.
|
|
174
|
+
*/
|
|
175
|
+
function parseAIResponse(text: string): AIDecision {
|
|
176
|
+
// Strip markdown code fences
|
|
177
|
+
const cleaned = text
|
|
178
|
+
.replace(/```json\n?/g, "")
|
|
179
|
+
.replace(/```/g, "")
|
|
180
|
+
.trim();
|
|
181
|
+
|
|
182
|
+
// Try direct parse first (ideal case)
|
|
183
|
+
try {
|
|
184
|
+
return JSON.parse(cleaned);
|
|
185
|
+
} catch {
|
|
186
|
+
// Not pure JSON — try to extract a JSON object from the text
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Look for a JSON object embedded in prose: find outermost { ... }
|
|
190
|
+
const start = cleaned.indexOf("{");
|
|
191
|
+
const end = cleaned.lastIndexOf("}");
|
|
192
|
+
if (start !== -1 && end > start) {
|
|
193
|
+
try {
|
|
194
|
+
return JSON.parse(cleaned.slice(start, end + 1));
|
|
195
|
+
} catch {
|
|
196
|
+
// Malformed JSON block — fall through
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Model responded with pure prose — treat it as a "wait" action
|
|
201
|
+
// so the loop continues instead of crashing
|
|
202
|
+
console.log(` [AI] Non-JSON response, treating as wait: "${cleaned.slice(0, 80)}..."`);
|
|
203
|
+
return {
|
|
204
|
+
action: "wait",
|
|
205
|
+
reasoning: cleaned.slice(0, 200),
|
|
206
|
+
amount: 2000,
|
|
207
|
+
};
|
|
173
208
|
}
|