Spaces:
Sleeping
Sleeping
wuyiqunLu
commited on
feat: enqueue final error to ui on streaming error and timeout (#83)
Browse files
<img width="1423" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/c2cb87c1-aed5-42a4-802d-1b75bab0968e">
- app/api/vision-agent/route.ts +18 -4
- lib/utils/content.ts +1 -50
app/api/vision-agent/route.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { getPresignedUrl } from '@/lib/aws';
|
|
| 11 |
// export const runtime = 'edge';
|
| 12 |
export const dynamic = 'force-dynamic';
|
| 13 |
export const maxDuration = 300; // This function can run for a maximum of 5 minutes
|
| 14 |
-
const TIMEOUT_MILI_SECONDS =
|
| 15 |
|
| 16 |
const uploadBase64 = async (
|
| 17 |
base64: string,
|
|
@@ -172,9 +172,21 @@ export const POST = withLogging(
|
|
| 172 |
request,
|
| 173 |
'__Agent_timeout__',
|
| 174 |
);
|
| 175 |
-
controller.
|
| 176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
);
|
|
|
|
|
|
|
| 178 |
}
|
| 179 |
} else {
|
| 180 |
time = Date.now();
|
|
@@ -187,6 +199,9 @@ export const POST = withLogging(
|
|
| 187 |
) => {
|
| 188 |
try {
|
| 189 |
const msg = JSON.parse(line);
|
|
|
|
|
|
|
|
|
|
| 190 |
if (
|
| 191 |
msg.type !== 'final_code' &&
|
| 192 |
(msg.type !== 'code' ||
|
|
@@ -231,7 +246,6 @@ export const POST = withLogging(
|
|
| 231 |
if (mp4) result.results[index].mp4 = resp;
|
| 232 |
}
|
| 233 |
msg.payload.result = JSON.stringify(result);
|
| 234 |
-
done = true;
|
| 235 |
return JSON.stringify(msg);
|
| 236 |
} catch (e) {
|
| 237 |
errorCallback?.(e as Error);
|
|
|
|
| 11 |
// export const runtime = 'edge';
|
| 12 |
export const dynamic = 'force-dynamic';
|
| 13 |
export const maxDuration = 300; // This function can run for a maximum of 5 minutes
|
| 14 |
+
const TIMEOUT_MILI_SECONDS = 2 * 60 * 1000;
|
| 15 |
|
| 16 |
const uploadBase64 = async (
|
| 17 |
base64: string,
|
|
|
|
| 172 |
request,
|
| 173 |
'__Agent_timeout__',
|
| 174 |
);
|
| 175 |
+
controller.enqueue(
|
| 176 |
+
encoder.encode(
|
| 177 |
+
JSON.stringify({
|
| 178 |
+
type: 'final_error',
|
| 179 |
+
status: 'failed',
|
| 180 |
+
payload: {
|
| 181 |
+
name: 'AgentTimeout',
|
| 182 |
+
value: `Haven't received any response in last ${TIMEOUT_MILI_SECONDS / 60000} minutes, agent timed out.`,
|
| 183 |
+
traceback_raw: [],
|
| 184 |
+
},
|
| 185 |
+
}) + '\n',
|
| 186 |
+
),
|
| 187 |
);
|
| 188 |
+
controller.close();
|
| 189 |
+
return;
|
| 190 |
}
|
| 191 |
} else {
|
| 192 |
time = Date.now();
|
|
|
|
| 199 |
) => {
|
| 200 |
try {
|
| 201 |
const msg = JSON.parse(line);
|
| 202 |
+
if (msg.type === 'final_code' || msg.type === 'final_error') {
|
| 203 |
+
done = true;
|
| 204 |
+
}
|
| 205 |
if (
|
| 206 |
msg.type !== 'final_code' &&
|
| 207 |
(msg.type !== 'code' ||
|
|
|
|
| 246 |
if (mp4) result.results[index].mp4 = resp;
|
| 247 |
}
|
| 248 |
msg.payload.result = JSON.stringify(result);
|
|
|
|
| 249 |
return JSON.stringify(msg);
|
| 250 |
} catch (e) {
|
| 251 |
errorCallback?.(e as Error);
|
lib/utils/content.ts
CHANGED
|
@@ -72,55 +72,6 @@ type ReflectionBody =
|
|
| 72 |
payload: { feedback: string; success: boolean };
|
| 73 |
};
|
| 74 |
|
| 75 |
-
type MessageBody =
|
| 76 |
-
| PlansBody
|
| 77 |
-
| ToolsBody
|
| 78 |
-
| CodeBody
|
| 79 |
-
| ReflectionBody
|
| 80 |
-
| PrismaJson.FinalChatResult;
|
| 81 |
-
|
| 82 |
-
const getMessageTitle = (json: MessageBody) => {
|
| 83 |
-
switch (json.type) {
|
| 84 |
-
case 'plans':
|
| 85 |
-
if (json.status === 'started') {
|
| 86 |
-
return 'π¬ Start generating plans...\n';
|
| 87 |
-
} else {
|
| 88 |
-
return 'β
Going to run the following plan(s) in sequence:\n';
|
| 89 |
-
}
|
| 90 |
-
case 'tools':
|
| 91 |
-
if (json.status === 'started') {
|
| 92 |
-
return 'π¬ Start retrieving tools...\n';
|
| 93 |
-
} else {
|
| 94 |
-
return 'β
Tools retrieved:\n';
|
| 95 |
-
}
|
| 96 |
-
case 'code':
|
| 97 |
-
if (json.status === 'started') {
|
| 98 |
-
return 'π¬ Start generating code...\n';
|
| 99 |
-
} else if (json.status === 'running') {
|
| 100 |
-
return 'π¬ Code generated, start execution... ';
|
| 101 |
-
} else if (json.status === 'completed') {
|
| 102 |
-
return 'β
Code executed successfully. ';
|
| 103 |
-
} else {
|
| 104 |
-
return 'β Code execution failed. ';
|
| 105 |
-
}
|
| 106 |
-
case 'self_reflection':
|
| 107 |
-
if (json.status === 'started') {
|
| 108 |
-
return 'π¬ Start self reflection...\n';
|
| 109 |
-
} else if (json.status === 'completed') {
|
| 110 |
-
return 'β
Self reflection completed: \n';
|
| 111 |
-
} else {
|
| 112 |
-
return 'β Self reflection failed: \n';
|
| 113 |
-
}
|
| 114 |
-
case 'final_code':
|
| 115 |
-
if (json.status === 'completed') {
|
| 116 |
-
return 'β
The vision agent has concluded the chat, the last execution is successful. \n';
|
| 117 |
-
} else {
|
| 118 |
-
return 'β The vision agent has concluded the chat, the last execution is failed. \n';
|
| 119 |
-
}
|
| 120 |
-
default:
|
| 121 |
-
throw 'Not supported type';
|
| 122 |
-
}
|
| 123 |
-
};
|
| 124 |
|
| 125 |
export type CodeResult = {
|
| 126 |
code: string;
|
|
@@ -130,7 +81,7 @@ export type CodeResult = {
|
|
| 130 |
|
| 131 |
export type ChunkBody =
|
| 132 |
| {
|
| 133 |
-
type: 'plans' | 'tools' | 'code' | 'final_code';
|
| 134 |
status: 'started' | 'completed' | 'failed' | 'running';
|
| 135 |
payload:
|
| 136 |
| Array<Record<string, string>> // PlansBody | ToolsBody
|
|
|
|
| 72 |
payload: { feedback: string; success: boolean };
|
| 73 |
};
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
export type CodeResult = {
|
| 77 |
code: string;
|
|
|
|
| 81 |
|
| 82 |
export type ChunkBody =
|
| 83 |
| {
|
| 84 |
+
type: 'plans' | 'tools' | 'code' | 'final_code' | 'final_error';
|
| 85 |
status: 'started' | 'completed' | 'failed' | 'running';
|
| 86 |
payload:
|
| 87 |
| Array<Record<string, string>> // PlansBody | ToolsBody
|