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
|