Ship Assistent 0.15.2: apply closed generate patches immediately, recover stalled streams, and skip repeat greetings when a chat already has replies.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-23 09:28:04 +03:00
co-authored by Cursor
parent 4b36850e2b
commit e53f483a00
19 changed files with 790 additions and 287 deletions
+27 -18
View File
@@ -59,7 +59,11 @@ export function normalizeDelta(raw) {
}
const delta = { ...raw };
const acts = Array.isArray(delta.actions) ? delta.actions.map(String) : [];
if (delta.generate === true || acts.includes('generate')) {
const g = delta.generate;
const generateOn = g === true || g === 1
|| (typeof g === 'string' && /^(true|1|yes|on)$/i.test(g.trim()))
|| acts.includes('generate');
if (generateOn) {
delta.generate = true;
}
if (typeof delta.ask === 'string') {
@@ -77,7 +81,8 @@ export function patchWantsGenerate(patch) {
if (!patch || typeof patch !== 'object') {
return false;
}
if (patch.generate === true) {
const n = normalizeDelta(patch);
if (n?.generate === true) {
return true;
}
const acts = Array.isArray(patch.actions) ? patch.actions.map(String) : [];
@@ -340,10 +345,14 @@ export function fullSettingsDump(session, extras = {}) {
};
}
export function resolveTurnIntent(patch, userText, { vetoFn } = {}) {
/** Model generate/actions, or askGenerateFn when a prompt/delta exists. vetoFn / fromAutoCritique cancel. */
export function resolveTurnIntent(patch, userText, { vetoFn, askGenerateFn, fromAutoCritique } = {}) {
const delta = normalizeDelta(patch) || {};
const vetoed = typeof vetoFn === 'function' ? !!vetoFn(userText) : false;
const generate = !vetoed && patchWantsGenerate(delta);
const modelAsked = patchWantsGenerate(delta);
const userAsked = typeof askGenerateFn === 'function' && !!askGenerateFn(userText)
&& !!(modelAsked || String(delta.prompt || '').trim());
const generate = !vetoed && !fromAutoCritique && (modelAsked || userAsked);
const hasLook = delta.look_at != null || delta.vision_from != null || delta.vision_slots != null;
const look = !!(hasLook && !generate && !vetoed);
const ask = patchAskList(delta);
@@ -390,20 +399,20 @@ export function mergeExactParamsForGenerate(patch, {
const defaults = resolveExactProfileDefaults({ exact, profiles, profileName });
const out = { ...patch };
const clearSessionKeys = [];
for (const key of EXACT_GENERATE_PARAM_KEYS) {
if (out[key] != null) {
// Sparse LLM may echo live leftovers (20/7). Without user intent, force Exact.
if (
!userParamIntent
&& defaults[key] != null
&& String(out[key]) !== String(defaults[key])
) {
out[key] = defaults[key];
if (sessionExact?.[key] != null && String(sessionExact[key]) !== String(defaults[key])) {
clearSessionKeys.push(key);
}
}
continue;
for (const key of EXACT_GENERATE_PARAM_KEYS) {
if (out[key] != null) {
// Sparse LLM may echo live leftovers (20/7). Without user intent, force Exact.
if (
!userParamIntent
&& defaults[key] != null
&& String(out[key]) !== String(defaults[key])
) {
out[key] = defaults[key];
if (sessionExact?.[key] != null && String(sessionExact[key]) !== String(defaults[key])) {
clearSessionKeys.push(key);
}
}
continue;
}
if (userParamIntent && sessionExact?.[key] != null) {
out[key] = sessionExact[key];