-
Notifications
You must be signed in to change notification settings - Fork 970
fix(host-service): time out AI workspace naming after 5s #4102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,6 +9,7 @@ import { deduplicateBranchName } from "./sanitize-branch"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const WORKSPACE_TITLE_MAX = 150; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const BRANCH_NAME_MAX = 25; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const GENERATE_TIMEOUT_MS = 5_000; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/host-service/src/trpc/router/workspace-creation/utils/ai-workspace-names.ts
Line: 12
Comment:
`GENERATE_TIMEOUT_MS` is now declared independently in both `ai-workspace-names.ts` and `ai-branch-name.ts`. If the desired timeout is ever adjusted, both files must be updated in sync — a silent divergence risk. Consider moving this constant to a shared `constants.ts` (or `ai-utils.ts`) in the same `utils/` directory and importing it from both call-sites.
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function sanitizeBranchCandidate(raw: string): string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return raw | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -81,12 +82,20 @@ export async function generateWorkspaceNamesFromPrompt( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { object } = await agent.generate(cleaned, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| structuredOutput: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| schema: workspaceNamesSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jsonPromptInjection: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { object } = await Promise.race([ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| agent.generate(cleaned, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| structuredOutput: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| schema: workspaceNamesSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jsonPromptInjection: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new Promise<never>((_, reject) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GENERATE_TIMEOUT_MS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+85
to
+98
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clear the timeout handle when When the LLM responds before 5 s the 🛠️ Proposed fix try {
- const { object } = await Promise.race([
- agent.generate(cleaned, {
- structuredOutput: {
- schema: workspaceNamesSchema,
- jsonPromptInjection: true,
- },
- }),
- new Promise<never>((_, reject) =>
- setTimeout(
- () => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)),
- GENERATE_TIMEOUT_MS,
- ),
- ),
- ]);
+ let timeoutId: ReturnType<typeof setTimeout>;
+ const { object } = await Promise.race([
+ agent.generate(cleaned, {
+ structuredOutput: {
+ schema: workspaceNamesSchema,
+ jsonPromptInjection: true,
+ },
+ }),
+ new Promise<never>((_, reject) => {
+ timeoutId = setTimeout(
+ () => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)),
+ GENERATE_TIMEOUT_MS,
+ );
+ }),
+ ]).finally(() => clearTimeout(timeoutId));
return object;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return object; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
84
to
100
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Prompt To Fix With AIThis is a comment left during a code review.
Path: packages/host-service/src/trpc/router/workspace-creation/utils/ai-workspace-names.ts
Line: 84-100
Comment:
Timer leak on the happy path: when `agent.generate` resolves before the 5 s deadline, the `setTimeout` callback is never cancelled. The timer fires 5 seconds later, calls `reject` on an already-settled promise (harmless but wasteful), and the dangling handle keeps the garbage collector from reclaiming the closure. Under load, many concurrent workspace-creation calls will accumulate dozens of live timers simultaneously. Clearing the handle when the race resolves avoids this.
```suggestion
let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
try {
const { object } = await Promise.race([
agent.generate(cleaned, {
structuredOutput: {
schema: workspaceNamesSchema,
jsonPromptInjection: true,
},
}),
new Promise<never>((_, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)),
GENERATE_TIMEOUT_MS,
);
}),
]);
clearTimeout(timeoutHandle);
return object;
} catch (error) {
clearTimeout(timeoutHandle);
```
How can I resolve this? If you propose a fix, please make it concise. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same timer-leak as in
ai-workspace-names.ts— clear the timeout handle.The
setTimeoutfires even whengenerateTitleFromMessagecompletes within 5 s. The samefinally(() => clearTimeout(timeoutId))fix applies here.🛠️ Proposed fix
try { - generated = await Promise.race([ - generateTitleFromMessage({ - message: prompt, - agentModel: model, - agentId: "branch-namer", - agentName: "Branch Namer", - instructions: BRANCH_NAME_INSTRUCTIONS, - tracingContext: { surface: "host-service-branch-name" }, - }), - new Promise<never>((_, reject) => - setTimeout( - () => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)), - GENERATE_TIMEOUT_MS, - ), - ), - ]); + let timeoutId: ReturnType<typeof setTimeout>; + generated = await Promise.race([ + generateTitleFromMessage({ + message: prompt, + agentModel: model, + agentId: "branch-namer", + agentName: "Branch Namer", + instructions: BRANCH_NAME_INSTRUCTIONS, + tracingContext: { surface: "host-service-branch-name" }, + }), + new Promise<never>((_, reject) => { + timeoutId = setTimeout( + () => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)), + GENERATE_TIMEOUT_MS, + ); + }), + ]).finally(() => clearTimeout(timeoutId));📝 Committable suggestion
🤖 Prompt for AI Agents