@youdie006/prodex 0.40.5 → 0.40.6
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/chatgpt-browser.js +44 -3
- package/dist/cli-pro.js +25 -3
- package/package.json +1 -1
package/dist/chatgpt-browser.js
CHANGED
|
@@ -5396,7 +5396,10 @@ export function recentConversationsExpression(limit = 4) {
|
|
|
5396
5396
|
}
|
|
5397
5397
|
const user = chain.find((entry) => entry && entry.author && entry.author.role === "user" && entry.content);
|
|
5398
5398
|
const text = user ? (user.content.parts || []).filter((part) => typeof part === "string").join("") : "";
|
|
5399
|
-
|
|
5399
|
+
// Long enough that two consults sharing an opening can still be told
|
|
5400
|
+
// apart by the rest of the prompt; bounded so a huge --file send does
|
|
5401
|
+
// not drag its whole payload back through the bridge.
|
|
5402
|
+
out.push({ id: item.id, userText: text.slice(0, 4000) });
|
|
5400
5403
|
} catch (error) {
|
|
5401
5404
|
// A conversation we cannot read is simply not a match.
|
|
5402
5405
|
}
|
|
@@ -5404,9 +5407,47 @@ export function recentConversationsExpression(limit = 4) {
|
|
|
5404
5407
|
return out;
|
|
5405
5408
|
})()`;
|
|
5406
5409
|
}
|
|
5407
|
-
/**
|
|
5410
|
+
/**
|
|
5411
|
+
* Which of those conversations is the one this send posted into, if any.
|
|
5412
|
+
*
|
|
5413
|
+
* Identity is a PREFIX test - the first 120 normalized characters - because a
|
|
5414
|
+
* composer tool prefixes the prompt and attachments append to it, so neither
|
|
5415
|
+
* end is reliable on its own. Two consults that open the same way therefore
|
|
5416
|
+
* look identical to it, which is not hypothetical: an agent working from a
|
|
5417
|
+
* template, or a debate loop, repeats its opening every round. Taking the
|
|
5418
|
+
* first match then reads an OLDER conversation and returns its answer as this
|
|
5419
|
+
* send's - measured on two prompts sharing a 125-character preamble and
|
|
5420
|
+
* differing at character 142, where sending the newer one picked the older.
|
|
5421
|
+
*
|
|
5422
|
+
* So an ambiguous prefix is resolved by the whole prompt, and if that cannot
|
|
5423
|
+
* single one out either, nothing is picked. The caller falls back to its other
|
|
5424
|
+
* evidence, which costs a wait; picking wrong costs the wrong answer.
|
|
5425
|
+
*/
|
|
5408
5426
|
export function pickLandedConversation(candidates, sentPrompt) {
|
|
5409
|
-
|
|
5427
|
+
const matches = candidates.filter((candidate) => transcriptMatchesSentPrompt(candidate.userText, sentPrompt));
|
|
5428
|
+
if (matches.length <= 1)
|
|
5429
|
+
return matches[0]?.id;
|
|
5430
|
+
const whole = matches.filter((candidate) => transcriptContainsWholeSentPrompt(candidate.userText, sentPrompt));
|
|
5431
|
+
return whole.length === 1 ? whole[0].id : undefined;
|
|
5432
|
+
}
|
|
5433
|
+
/**
|
|
5434
|
+
* The stricter test, for telling apart conversations the prefix cannot.
|
|
5435
|
+
*
|
|
5436
|
+
* Still a containment test - the transcript wraps the prompt - but of the
|
|
5437
|
+
* whole prompt rather than its opening. A prompt longer than the recorded
|
|
5438
|
+
* sample cannot match, which leaves the caller with nothing to pick, and
|
|
5439
|
+
* nothing is the safe answer here.
|
|
5440
|
+
*/
|
|
5441
|
+
export function transcriptContainsWholeSentPrompt(userText, sentPrompt) {
|
|
5442
|
+
const normalize = (value) => value
|
|
5443
|
+
.replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1")
|
|
5444
|
+
.replace(/\s+/g, " ")
|
|
5445
|
+
.trim();
|
|
5446
|
+
const seen = normalize(userText);
|
|
5447
|
+
const sent = normalize(sentPrompt);
|
|
5448
|
+
if (seen.length === 0 || sent.length === 0)
|
|
5449
|
+
return false;
|
|
5450
|
+
return seen.includes(sent);
|
|
5410
5451
|
}
|
|
5411
5452
|
export function transcriptAnswerExpression(conversationId) {
|
|
5412
5453
|
return `(async () => {
|
package/dist/cli-pro.js
CHANGED
|
@@ -1352,6 +1352,11 @@ export async function runAskProCommand(rest, io) {
|
|
|
1352
1352
|
const autoLoginAllowed = !parsedAskPro.optionArgs.includes("--no-auto-login") &&
|
|
1353
1353
|
(parsedAskPro.optionArgs.includes("--auto-login") || io.isInteractive === true);
|
|
1354
1354
|
let consult;
|
|
1355
|
+
// Declared out here so a retry that fails still reports what recovery
|
|
1356
|
+
// did: the notes used to live inside the inner catch and were attached
|
|
1357
|
+
// to the ANSWER, so a recovered browser whose retry then died recorded
|
|
1358
|
+
// nothing about the recovery at all.
|
|
1359
|
+
const recoveryNotes = [];
|
|
1355
1360
|
try {
|
|
1356
1361
|
try {
|
|
1357
1362
|
consult = await sendOnce();
|
|
@@ -1360,7 +1365,6 @@ export async function runAskProCommand(rest, io) {
|
|
|
1360
1365
|
const firstBlocker = browserSendBlockerFromError(error);
|
|
1361
1366
|
if (firstBlocker.code !== "browser_unreachable" || !autoLoginAllowed)
|
|
1362
1367
|
throw error;
|
|
1363
|
-
const recoveryNotes = [];
|
|
1364
1368
|
const recovered = await attemptBrowserAutoRecovery(io.stderr, {
|
|
1365
1369
|
...(browserPort !== undefined ? { port: browserPort } : {}),
|
|
1366
1370
|
notes: recoveryNotes
|
|
@@ -1387,7 +1391,7 @@ export async function runAskProCommand(rest, io) {
|
|
|
1387
1391
|
// What the send had already noticed before it died. These used to go
|
|
1388
1392
|
// out with the result, so a failure dropped them - including the note
|
|
1389
1393
|
// that would explain it, like having just moved off the Work surface.
|
|
1390
|
-
const blockedWarnings = sendWarningsFromError(error).map(redactProject);
|
|
1394
|
+
const blockedWarnings = [...recoveryNotes, ...sendWarningsFromError(error)].map(redactProject);
|
|
1391
1395
|
for (const warning of blockedWarnings)
|
|
1392
1396
|
io.stderr(warning);
|
|
1393
1397
|
const persistedBlocker = {
|
|
@@ -1797,6 +1801,20 @@ function autoClearDisabledByEnv(env = process.env) {
|
|
|
1797
1801
|
const raw = (env.PRODEX_NO_AUTO_CLEAR ?? "").trim().toLowerCase();
|
|
1798
1802
|
return raw === "1" || raw === "true" || raw === "yes";
|
|
1799
1803
|
}
|
|
1804
|
+
/**
|
|
1805
|
+
* What recovery did to the browser, in the words the receipt keeps.
|
|
1806
|
+
*
|
|
1807
|
+
* Both halves are recorded because both change what the answer came from. The
|
|
1808
|
+
* ending case takes someone's running browser with it; the launch case is the
|
|
1809
|
+
* quieter one and used to record nothing at all - measured, killing the
|
|
1810
|
+
* dedicated browser and sending with --auto-login recovered in three seconds
|
|
1811
|
+
* and left warnings: [] on the receipt, the result and the task.
|
|
1812
|
+
*/
|
|
1813
|
+
export function browserRecoveredNote(ended) {
|
|
1814
|
+
return ended.length > 0
|
|
1815
|
+
? `browser_recovered: the dedicated browser stopped answering its control port and prodex ended it (pid ${ended.join(", ")}) and started a fresh one before sending. Anything it was doing at the time is gone; the profile and login were kept.`
|
|
1816
|
+
: "browser_recovered: the dedicated browser was not running, so prodex started it with the saved profile before sending. The login was kept; anything the old browser had open is gone.";
|
|
1817
|
+
}
|
|
1800
1818
|
export async function attemptBrowserAutoRecovery(stderr, options) {
|
|
1801
1819
|
// Launching is right when the browser is gone and wrong when it is only deaf:
|
|
1802
1820
|
// a second Chrome on the same profile joins the wedged one rather than
|
|
@@ -1831,7 +1849,7 @@ export async function attemptBrowserAutoRecovery(stderr, options) {
|
|
|
1831
1849
|
stderr(`recover: the browser stopped answering; ending it (pid ${wedged.join(", ")}) and starting a fresh one...`);
|
|
1832
1850
|
// Ending someone's browser is not a progress line to scroll past: it goes on
|
|
1833
1851
|
// the receipt, where an agent or a person reading `pro latest` will see it.
|
|
1834
|
-
options.notes?.push(
|
|
1852
|
+
options.notes?.push(browserRecoveredNote(wedged));
|
|
1835
1853
|
await endWedgedBrowser(wedged);
|
|
1836
1854
|
// Wait for the profile lock to actually clear rather than guessing at a
|
|
1837
1855
|
// delay: the replacement launch fails outright if the old process still
|
|
@@ -1874,6 +1892,10 @@ export async function attemptBrowserAutoRecovery(stderr, options) {
|
|
|
1874
1892
|
stderr("recover: window minimized again");
|
|
1875
1893
|
}
|
|
1876
1894
|
stderr("recover: browser READY - retrying the send...");
|
|
1895
|
+
// The wedged branch above records what it ended; this branch records that
|
|
1896
|
+
// the browser was gone and this answer came from one prodex started.
|
|
1897
|
+
if (wedged.length === 0)
|
|
1898
|
+
options.notes?.push(browserRecoveredNote([]));
|
|
1877
1899
|
return true;
|
|
1878
1900
|
}
|
|
1879
1901
|
catch (error) {
|