Skip to content

Commit 4631c5b

Browse files
committed
refactor(ui-tars-sdk): unify error handling logic in SDK
1 parent 956e451 commit 4631c5b

File tree

2 files changed

+119
-37
lines changed

2 files changed

+119
-37
lines changed

packages/ui-tars/sdk/src/GUIAgent.ts

+109-31
Original file line numberDiff line numberDiff line change
@@ -146,17 +146,24 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
146146
break;
147147
}
148148

149-
if (loopCnt >= maxLoopCount || snapshotErrCnt >= MAX_SNAPSHOT_ERR_CNT) {
149+
if (loopCnt >= maxLoopCount) {
150150
Object.assign(data, {
151-
status:
152-
loopCnt >= maxLoopCount ? StatusEnum.MAX_LOOP : StatusEnum.ERROR,
153-
...(snapshotErrCnt >= MAX_SNAPSHOT_ERR_CNT && {
154-
error: {
155-
code: ErrorStatusEnum.SCREENSHOT_ERROR,
156-
error: 'Too many screenshot failures',
157-
stack: 'null',
158-
},
159-
}),
151+
status: StatusEnum.ERROR,
152+
...this.guiAgentErrorParser(
153+
null,
154+
ErrorStatusEnum.REACH_MAXLOOP_ERROR,
155+
),
156+
});
157+
break;
158+
}
159+
160+
if (snapshotErrCnt >= MAX_SNAPSHOT_ERR_CNT) {
161+
Object.assign(data, {
162+
status: StatusEnum.ERROR,
163+
...this.guiAgentErrorParser(
164+
null,
165+
ErrorStatusEnum.SCREENSHOT_RETRY_ERROR,
166+
),
160167
});
161168
break;
162169
}
@@ -251,7 +258,19 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
251258
parsedPredictions: [],
252259
};
253260
}
254-
throw error;
261+
262+
Object.assign(data, {
263+
status: StatusEnum.ERROR,
264+
...this.guiAgentErrorParser(
265+
error,
266+
ErrorStatusEnum.INVOKE_RETRY_ERROR,
267+
),
268+
});
269+
270+
return {
271+
prediction: '',
272+
parsedPredictions: [],
273+
};
255274
}
256275
},
257276
{
@@ -260,14 +279,14 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
260279
},
261280
);
262281

263-
logger.info('[GUIAgent Response]:', prediction);
282+
logger.info('[GUIAgent] Response:', prediction);
264283
logger.info(
265-
'GUIAgent Parsed Predictions:',
284+
'[GUIAgent] Parsed Predictions:',
266285
JSON.stringify(parsedPredictions),
267286
);
268287

269288
if (!prediction) {
270-
logger.error('[GUIAgent Response Empty]:', prediction);
289+
logger.error('[GUIAgent] Response Empty:', prediction);
271290
continue;
272291
}
273292

@@ -302,27 +321,32 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
302321
for (const parsedPrediction of parsedPredictions) {
303322
const actionType = parsedPrediction.action_type;
304323

305-
logger.info('GUIAgent Action:', actionType);
324+
logger.info('[GUIAgent] Action:', actionType);
306325

307326
// handle internal action spaces
308327
if (actionType === INTERNAL_ACTION_SPACES_ENUM.ERROR_ENV) {
309328
Object.assign(data, {
310329
status: StatusEnum.ERROR,
311-
error: {
312-
code: ErrorStatusEnum.ENVIRONMENT_ERROR,
313-
error: 'The environment error occurred when parsing the action',
314-
stack: 'null',
315-
},
330+
error: this.guiAgentErrorParser(
331+
null,
332+
ErrorStatusEnum.ENVIRONMENT_ERROR,
333+
),
316334
});
317335
break;
318336
} else if (actionType === INTERNAL_ACTION_SPACES_ENUM.MAX_LOOP) {
319-
data.status = StatusEnum.MAX_LOOP;
337+
Object.assign(data, {
338+
status: StatusEnum.ERROR,
339+
error: this.guiAgentErrorParser(
340+
null,
341+
ErrorStatusEnum.REACH_MAXLOOP_ERROR,
342+
),
343+
});
320344
break;
321345
}
322346

323347
if (!signal?.aborted && !this.isStopped) {
324348
logger.info(
325-
'GUIAgent Action Inputs:',
349+
'[GUIAgent] Action Inputs:',
326350
parsedPrediction.action_inputs,
327351
parsedPrediction.action_type,
328352
);
@@ -342,7 +366,14 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
342366
onRetry: retry?.execute?.onRetry,
343367
},
344368
).catch((e) => {
345-
logger.error('GUIAgent execute error', e);
369+
logger.error('[GUIAgent] execute error', e);
370+
Object.assign(data, {
371+
status: StatusEnum.ERROR,
372+
...this.guiAgentErrorParser(
373+
e,
374+
ErrorStatusEnum.EXECUTE_RETRY_ERROR,
375+
),
376+
});
346377
});
347378

348379
if (executeOutput && executeOutput?.status) {
@@ -371,21 +402,23 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
371402
}
372403
}
373404
} catch (error) {
374-
logger.error('[GUIAgent] run, catch error', error);
405+
logger.error('[GUIAgent] Catch error', error);
375406
if (
376407
error instanceof Error &&
377408
(error.name === 'AbortError' || error.message?.includes('aborted'))
378409
) {
379-
logger.info('Request was aborted');
410+
logger.info('[GUIAgent] Catch: request was aborted');
380411
data.status = StatusEnum.USER_STOPPED;
381412
return;
382413
}
383414

384415
data.status = StatusEnum.ERROR;
385-
data.error = this.guiAgentErrorParser(error as Error) as GUIAgentError;
416+
data.error = this.guiAgentErrorParser(error);
386417

387418
throw error;
388419
} finally {
420+
logger.info('[GUIAgent] Finally: status', data.status);
421+
389422
if (data.status === StatusEnum.USER_STOPPED) {
390423
await operator.execute({
391424
prediction: '',
@@ -401,18 +434,18 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
401434
factors: [0, 0],
402435
});
403436
}
437+
404438
await onData?.({ data: { ...data, conversations: [] } });
439+
405440
if (data.status === StatusEnum.ERROR) {
406441
onError?.({
407442
data,
408443
error: data.error || {
409444
code: ErrorStatusEnum.UNKNOWN_ERROR,
410445
error: 'Unkown error occurred',
411-
stack: 'null',
412446
},
413447
});
414448
}
415-
logger.info('[GUIAgent] finally: status', data.status);
416449
}
417450
}
418451

@@ -448,7 +481,10 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
448481
);
449482
}
450483

451-
private guiAgentErrorParser(error: unknown): GUIAgentError {
484+
private guiAgentErrorParser(
485+
error: unknown,
486+
type: ErrorStatusEnum | null = null,
487+
): GUIAgentError {
452488
if (
453489
error instanceof Error &&
454490
'status' in error &&
@@ -459,14 +495,56 @@ export class GUIAgent<T extends Operator> extends BaseGUIAgent<
459495
) {
460496
return {
461497
code: ErrorStatusEnum.MODEL_SERVICE_ERROR,
462-
error: error.message,
498+
error: error.error,
463499
stack: error.stack,
500+
detail: JSON.stringify(error),
501+
};
502+
}
503+
504+
if (type === ErrorStatusEnum.REACH_MAXLOOP_ERROR) {
505+
return {
506+
code: ErrorStatusEnum.REACH_MAXLOOP_ERROR,
507+
error: 'Has reached max loop count',
464508
};
465509
}
510+
511+
if (type === ErrorStatusEnum.SCREENSHOT_RETRY_ERROR) {
512+
return {
513+
code: ErrorStatusEnum.SCREENSHOT_RETRY_ERROR,
514+
error: 'Too many screenshot failures',
515+
};
516+
}
517+
518+
if (type === ErrorStatusEnum.INVOKE_RETRY_ERROR) {
519+
return {
520+
code: ErrorStatusEnum.INVOKE_RETRY_ERROR,
521+
error: 'Too many model invoke failures',
522+
stack: 'null',
523+
detail: JSON.stringify(error),
524+
};
525+
}
526+
527+
if (type === ErrorStatusEnum.EXECUTE_RETRY_ERROR) {
528+
return {
529+
code: ErrorStatusEnum.EXECUTE_RETRY_ERROR,
530+
error: 'Too many action execute failures',
531+
stack: 'null',
532+
detail: JSON.stringify(error),
533+
};
534+
}
535+
536+
if (type === ErrorStatusEnum.ENVIRONMENT_ERROR) {
537+
return {
538+
code: ErrorStatusEnum.ENVIRONMENT_ERROR,
539+
error: 'The environment error occurred when parsing the action',
540+
};
541+
}
542+
466543
return {
467544
code: ErrorStatusEnum.UNKNOWN_ERROR,
468545
error: 'Unkown error occurred',
469-
stack: JSON.stringify(error),
546+
stack: 'null',
547+
detail: JSON.stringify(error),
470548
};
471549
}
472550
}

packages/ui-tars/shared/src/types/agent.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ export interface Message {
99

1010
export enum ErrorStatusEnum {
1111
/** 100000 */
12-
SCREENSHOT_ERROR = -100000,
12+
SCREENSHOT_RETRY_ERROR = -100000,
1313
/** 100001 */
14-
EXECUTE_ERROR = -100001,
14+
INVOKE_RETRY_ERROR = -100001,
1515
/** 100002 */
16-
ENVIRONMENT_ERROR = -100002,
16+
EXECUTE_RETRY_ERROR = -100002,
1717
/** 100003 */
18-
INVOKE_TIMEOUT_ERROR = -100003,
18+
MODEL_SERVICE_ERROR = -100003,
1919
/** 100004 */
20-
INVOKE_RETRY_ERROR = -100004,
20+
REACH_MAXLOOP_ERROR = -100004,
2121
/** 100005 */
22-
MODEL_SERVICE_ERROR = -100005,
22+
ENVIRONMENT_ERROR = -100005,
2323
/** 100099 */
2424
UNKNOWN_ERROR = -100099,
2525
}
@@ -28,6 +28,7 @@ export interface GUIAgentError {
2828
code: ErrorStatusEnum;
2929
error: string;
3030
stack?: string;
31+
detail?: string;
3132
}
3233

3334
export type Status = `${StatusEnum}`;
@@ -37,6 +38,9 @@ export enum StatusEnum {
3738
PAUSE = 'pause',
3839
END = 'end',
3940
CALL_USER = 'call_user',
41+
/**
42+
* @deprecated kept for backward compatibility
43+
*/
4044
MAX_LOOP = 'max_loop',
4145
USER_STOPPED = 'user_stopped',
4246
ERROR = 'error',

0 commit comments

Comments
 (0)