osai-agent 4.2.5 → 4.2.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/package.json
CHANGED
package/src/agent/loop/local.js
CHANGED
|
@@ -163,7 +163,7 @@ const systemPrompt = buildSystemPrompt(this._userOS, this.mode, {
|
|
|
163
163
|
|
|
164
164
|
if (this._shouldCancel()) return null;
|
|
165
165
|
|
|
166
|
-
if (retrying) { this.
|
|
166
|
+
if (retrying) { this.onRetryStatus(''); retrying = false; }
|
|
167
167
|
|
|
168
168
|
if (!fullResponse) return null;
|
|
169
169
|
|
|
@@ -186,7 +186,7 @@ const systemPrompt = buildSystemPrompt(this._userOS, this.mode, {
|
|
|
186
186
|
}
|
|
187
187
|
retrying = true;
|
|
188
188
|
const backoffMs = DEFAULTS.API_RETRY_DELAY * (attempt + 1);
|
|
189
|
-
this.
|
|
189
|
+
this.onRetryStatus(`Retrying in ${Math.ceil(backoffMs / 1000)}s...`);
|
|
190
190
|
const slept = await this._cancellableSleep(backoffMs);
|
|
191
191
|
if (!slept || this._shouldCancel()) return null;
|
|
192
192
|
}
|
package/src/agent/react-loop.js
CHANGED
|
@@ -39,7 +39,7 @@ export class AgentLoop {
|
|
|
39
39
|
onMarkdown, onThought, onToolStart, onToolResult, onObservation,
|
|
40
40
|
onError, onComplete, onTodos, onBlocked, onThinkingStart, onThinkingEnd,
|
|
41
41
|
onBadge, onConfirmPrompt, onAskUserPrompt, onPlanPrompt,
|
|
42
|
-
onStats, onConnectionChange, onUpdateLastText, readline, noConfirm = false,
|
|
42
|
+
onStats, onConnectionChange, onUpdateLastText, onRetryStatus, readline, noConfirm = false,
|
|
43
43
|
isSubagent = false, maxIterations = null, local = false,
|
|
44
44
|
}) {
|
|
45
45
|
this.device = device;
|
|
@@ -115,6 +115,7 @@ export class AgentLoop {
|
|
|
115
115
|
this.onPlanPrompt = onPlanPrompt || (() => {});
|
|
116
116
|
this.onStats = onStats || (() => {});
|
|
117
117
|
this.onConnectionChange = onConnectionChange || (() => {});
|
|
118
|
+
this.onRetryStatus = onRetryStatus || (() => {});
|
|
118
119
|
this.onUpdateLastText = onUpdateLastText || (() => {});
|
|
119
120
|
this.onStats(0);
|
|
120
121
|
}
|
|
@@ -299,7 +300,7 @@ export class AgentLoop {
|
|
|
299
300
|
this.iteration++;
|
|
300
301
|
logger.debug(`Iteration ${this.iteration}/${this._maxIterations}`);
|
|
301
302
|
|
|
302
|
-
if (iterationRetrying) { this.
|
|
303
|
+
if (iterationRetrying) { this.onRetryStatus(''); iterationRetrying = false; }
|
|
303
304
|
|
|
304
305
|
try {
|
|
305
306
|
const shouldContinue = await this._executeIteration();
|
|
@@ -332,7 +333,7 @@ export class AgentLoop {
|
|
|
332
333
|
if (this.iteration <= 1 && !this._shouldCancel()) {
|
|
333
334
|
logger.info('Retrying iteration after error...');
|
|
334
335
|
iterationRetrying = true;
|
|
335
|
-
this.
|
|
336
|
+
this.onRetryStatus(`Retrying after error: ${error.message}`);
|
|
336
337
|
this.iteration--;
|
|
337
338
|
const slept = await this._cancellableSleep(DEFAULTS.API_RETRY_DELAY);
|
|
338
339
|
if (!slept || this._shouldCancel()) break;
|
|
@@ -618,7 +619,7 @@ export class AgentLoop {
|
|
|
618
619
|
|
|
619
620
|
const backoffMs = DEFAULTS.API_RETRY_DELAY * (attempt + 1);
|
|
620
621
|
retrying = true;
|
|
621
|
-
this.
|
|
622
|
+
this.onRetryStatus(`Request failed (${response.status}) — retrying in ${Math.ceil(backoffMs / 1000)}s...`);
|
|
622
623
|
const slept = await this._cancellableSleep(backoffMs);
|
|
623
624
|
if (!slept || this._shouldCancel()) return null;
|
|
624
625
|
continue;
|
|
@@ -629,7 +630,7 @@ export class AgentLoop {
|
|
|
629
630
|
if (contentType.includes('application/json')) {
|
|
630
631
|
const json = await response.json();
|
|
631
632
|
if (json.content || json.message) {
|
|
632
|
-
if (retrying) { this.
|
|
633
|
+
if (retrying) { this.onRetryStatus(''); retrying = false; }
|
|
633
634
|
const textContent = json.content || json.message || '';
|
|
634
635
|
const cleanText = textContent
|
|
635
636
|
.replace(/^\s*\{(?:\\")?tool(?:\\")?\s*:\s*.*$/gim, '')
|
|
@@ -647,7 +648,7 @@ export class AgentLoop {
|
|
|
647
648
|
}
|
|
648
649
|
retrying = true;
|
|
649
650
|
const backoffMs = DEFAULTS.API_RETRY_DELAY * (attempt + 1);
|
|
650
|
-
this.
|
|
651
|
+
this.onRetryStatus(`Worker error — retrying in ${Math.ceil(backoffMs / 1000)}s...`);
|
|
651
652
|
const slept = await this._cancellableSleep(backoffMs);
|
|
652
653
|
if (!slept || this._shouldCancel()) return null;
|
|
653
654
|
continue;
|
|
@@ -655,7 +656,7 @@ export class AgentLoop {
|
|
|
655
656
|
return null;
|
|
656
657
|
}
|
|
657
658
|
|
|
658
|
-
if (retrying) { this.
|
|
659
|
+
if (retrying) { this.onRetryStatus(''); retrying = false; }
|
|
659
660
|
return response;
|
|
660
661
|
} catch (error) {
|
|
661
662
|
if (error.name === 'AbortError' || this._shouldCancel()) {
|
|
@@ -668,7 +669,7 @@ export class AgentLoop {
|
|
|
668
669
|
}
|
|
669
670
|
retrying = true;
|
|
670
671
|
const backoffMs = DEFAULTS.API_RETRY_DELAY * (attempt + 1);
|
|
671
|
-
this.
|
|
672
|
+
this.onRetryStatus(`Retrying in ${Math.ceil(backoffMs / 1000)}s...`);
|
|
672
673
|
const slept = await this._cancellableSleep(backoffMs);
|
|
673
674
|
if (!slept || this._shouldCancel()) return null;
|
|
674
675
|
}
|
package/src/agent/subagent.js
CHANGED
|
@@ -103,6 +103,9 @@ export async function runSubagent(parent, { prompt, description = '' }) {
|
|
|
103
103
|
onUpdateLastText: (text) => {
|
|
104
104
|
if (STREAM_SUBAGENT_TO_PARENT) parent.onUpdateLastText(text);
|
|
105
105
|
},
|
|
106
|
+
onRetryStatus: (text) => {
|
|
107
|
+
if (STREAM_SUBAGENT_TO_PARENT) parent.onRetryStatus(text);
|
|
108
|
+
},
|
|
106
109
|
onThought: (text) => {
|
|
107
110
|
if (STREAM_SUBAGENT_TO_PARENT) parent.onThought(text);
|
|
108
111
|
},
|
package/src/ui/App.js
CHANGED
|
@@ -719,6 +719,36 @@ export function App({ createAgentLoop, agentConfig, initialSession = null, onExi
|
|
|
719
719
|
updateLastEvent(ev => ({ ...ev, content: text }));
|
|
720
720
|
}
|
|
721
721
|
},
|
|
722
|
+
onRetryStatus: (text) => {
|
|
723
|
+
const arr = eventsRef.current;
|
|
724
|
+
const findRetryIdx = () => {
|
|
725
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
726
|
+
if (arr[i].type === 'retry_status') return i;
|
|
727
|
+
}
|
|
728
|
+
return -1;
|
|
729
|
+
};
|
|
730
|
+
if (!text) {
|
|
731
|
+
const idx = findRetryIdx();
|
|
732
|
+
if (idx !== -1) {
|
|
733
|
+
const newArr = [...arr];
|
|
734
|
+
newArr.splice(idx, 1);
|
|
735
|
+
eventsRef.current = newArr;
|
|
736
|
+
flushEventsToState(false);
|
|
737
|
+
}
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const cleanedText = sanitizeUiText(text);
|
|
741
|
+
if (!cleanedText.trim()) return;
|
|
742
|
+
const idx = findRetryIdx();
|
|
743
|
+
if (idx !== -1) {
|
|
744
|
+
const newArr = [...arr];
|
|
745
|
+
newArr[idx] = { ...newArr[idx], content: cleanedText };
|
|
746
|
+
eventsRef.current = newArr;
|
|
747
|
+
flushEventsToState(false);
|
|
748
|
+
} else {
|
|
749
|
+
addEvent({ type: 'retry_status', content: cleanedText });
|
|
750
|
+
}
|
|
751
|
+
},
|
|
722
752
|
onToolStart: (toolCall) => {
|
|
723
753
|
if (toolCall.tool === 'ASK_USER') return;
|
|
724
754
|
const uid = ++toolUiIdCounterRef.current;
|
|
@@ -928,6 +928,8 @@ function renderEvent(ev, i, events, expandedOutputIndexes, thoughtStreaming, exp
|
|
|
928
928
|
const expanded = thoughtId != null && expandedThoughtIds && expandedThoughtIds.has(thoughtId);
|
|
929
929
|
return h(CollapsibleThought, { key: `thought_${thoughtId ?? i}`, id: thoughtId, content: ev.content, expanded, streaming: thoughtStreaming, animate });
|
|
930
930
|
}
|
|
931
|
+
case 'retry_status':
|
|
932
|
+
return h(Box, { key: i, paddingLeft: 2 }, h(Text, { color: 'red' }, ev.content));
|
|
931
933
|
case 'text':
|
|
932
934
|
return h(TextContent, { key: i, content: ev.content, events, animate });
|
|
933
935
|
case 'tool_start':
|