-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
k #1786
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
k #1786
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -51,16 +51,17 @@ import { processToolCalls } from './utils'; | |||||
| import { env } from 'cloudflare:workers'; | ||||||
| import type { Connection } from 'agents'; | ||||||
| import { openai } from '@ai-sdk/openai'; | ||||||
| import { parseISO } from 'date-fns'; | ||||||
| import { createDb } from '../../db'; | ||||||
| import { DriverRpcDO } from './rpc'; | ||||||
| import { eq } from 'drizzle-orm'; | ||||||
| import { Effect } from 'effect'; | ||||||
|
|
||||||
| const decoder = new TextDecoder(); | ||||||
|
|
||||||
| const shouldDropTables = false; | ||||||
| const shouldDropTables = true; | ||||||
|
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. Hard-coding shouldDropTables to true causes the database table to be dropped on every start, leading to data loss Prompt for AI agents
Suggested change
|
||||||
| const maxCount = 20; | ||||||
| const shouldLoop = env.THREAD_SYNC_LOOP !== 'false'; | ||||||
| const shouldLoop = true; | ||||||
|
Comment on lines
+62
to
+64
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. 💡 Verification agent 🧩 Analysis chainVerify the table dropping configuration change. Setting Run this script to check if there are any safeguards or environment-specific handling for this setting: 🏁 Script executed: #!/bin/bash
# Search for any conditional logic around shouldDropTables usage
rg -A 5 -B 5 "shouldDropTables"Length of output: 1652 🏁 Script executed: #!/bin/bash
# Locate the dropTables method to inspect its implementation and assess any safeguards
rg -A5 -B5 "dropTables" -n --glob "*.ts"Length of output: 1728 Confirm and safeguard the table-dropping behavior The DROP TABLE IF EXISTS threads;because Please verify that:
Locations to review:
If this behavior isn’t intentional for production, please revert 🤖 Prompt for AI Agents |
||||||
| export class ZeroDriver extends AIChatAgent<typeof env> { | ||||||
| private foldersInSync: Map<string, boolean> = new Map(); | ||||||
| private syncThreadsInProgress: Map<string, boolean> = new Map(); | ||||||
|
|
@@ -168,10 +169,8 @@ export class ZeroDriver extends AIChatAgent<typeof env> { | |||||
| if (_connection) this.driver = connectionToDriver(_connection); | ||||||
| this.ctx.waitUntil(conn.end()); | ||||||
| this.ctx.waitUntil(this.syncThreads('inbox')); | ||||||
| if (env.NODE_ENV === 'production') { | ||||||
| this.ctx.waitUntil(this.syncThreads('sent')); | ||||||
| this.ctx.waitUntil(this.syncThreads('spam')); | ||||||
| } | ||||||
| this.ctx.waitUntil(this.syncThreads('sent')); | ||||||
| this.ctx.waitUntil(this.syncThreads('spam')); | ||||||
| } | ||||||
| } | ||||||
| async rawListThreads(params: { | ||||||
|
|
@@ -393,7 +392,12 @@ export class ZeroDriver extends AIChatAgent<typeof env> { | |||||
|
|
||||||
| if (latest) { | ||||||
| // Convert receivedOn to ISO format for proper sorting | ||||||
| const normalizedReceivedOn = new Date(latest.receivedOn).toISOString(); | ||||||
| let normalizedReceivedOn: string; | ||||||
| try { | ||||||
| normalizedReceivedOn = new Date(latest.receivedOn).toISOString(); | ||||||
| } catch (error) { | ||||||
|
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. Rename the unused catch parameter 'error' to '_error' to indicate it's intentionally unused, following the convention for unused variables. Spotted by Diamond (based on CI logs) |
||||||
| normalizedReceivedOn = new Date().toISOString(); | ||||||
| } | ||||||
|
|
||||||
| await env.THREADS_BUCKET.put(this.getThreadKey(threadId), JSON.stringify(threadData), { | ||||||
| customMetadata: { | ||||||
|
|
@@ -476,38 +480,74 @@ export class ZeroDriver extends AIChatAgent<typeof env> { | |||||
|
|
||||||
| this.foldersInSync.set(folder, true); | ||||||
|
|
||||||
| try { | ||||||
| let totalSynced = 0; | ||||||
| const self = this; | ||||||
|
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. Remove the 'self = this' aliasing and instead use arrow functions or bind methods to preserve the 'this' context where needed. Spotted by Diamond (based on CI logs) |
||||||
|
|
||||||
| const syncSingleThread = (threadId: string) => | ||||||
| Effect.gen(function* () { | ||||||
| yield* Effect.sleep(500); // Rate limiting delay | ||||||
| return yield* withRetry(Effect.tryPromise(() => self.syncThread({ threadId }))); | ||||||
| }).pipe( | ||||||
| Effect.catchAll((error) => { | ||||||
| console.error(`Failed to sync thread ${threadId}:`, error); | ||||||
| return Effect.succeed(null); | ||||||
| }), | ||||||
| ); | ||||||
|
Comment on lines
+483
to
+494
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. 🛠️ Refactor suggestion Address linting issue and consider error handling improvements. The - const self = this;
-
- const syncSingleThread = (threadId: string) =>
+ const syncSingleThread = (threadId: string) =>
Effect.gen(function* () {
yield* Effect.sleep(500); // Rate limiting delay
- return yield* withRetry(Effect.tryPromise(() => self.syncThread({ threadId })));
+ return yield* withRetry(Effect.tryPromise(() => this.syncThread({ threadId })));
}).pipe(
Effect.catchAll((error) => {
console.error(`Failed to sync thread ${threadId}:`, error);
return Effect.succeed(null);
}),
- );
+ ).bind(this);Also consider whether swallowing all errors in
🧰 Tools🪛 GitHub Actions: autofix.ci[warning] 483-483: typescript-eslint (no-this-alias): Unexpected aliasing of 'this' to local variable. Assigning a variable to this instead of properly using arrow lambdas may be a symptom of pre-ES6 practices or not managing scope well. 🤖 Prompt for AI Agents |
||||||
|
|
||||||
| const syncProgram = Effect.gen( | ||||||
| function* () { | ||||||
| let totalSynced = 0; | ||||||
| let pageToken: string | null = null; | ||||||
| let hasMore = true; | ||||||
| let _pageCount = 0; | ||||||
|
|
||||||
| while (hasMore) { | ||||||
| _pageCount++; | ||||||
|
|
||||||
| // Rate limiting delay between pages | ||||||
| yield* Effect.sleep(2000); | ||||||
|
|
||||||
| const result: IGetThreadsResponse = yield* Effect.tryPromise(() => | ||||||
| self.listWithRetry({ | ||||||
| folder, | ||||||
| maxResults: maxCount, | ||||||
| pageToken: pageToken || undefined, | ||||||
| }), | ||||||
| ); | ||||||
|
|
||||||
| // Process threads one by one without buffering | ||||||
| for await (const thread of this.streamThreads(folder)) { | ||||||
| try { | ||||||
| const id = await this.queue('syncThread', { threadId: thread.id }); | ||||||
| console.log(`Synced thread ${thread.id} to queue ${id}`); | ||||||
| totalSynced++; | ||||||
| } catch (error) { | ||||||
| console.error(`Failed to sync thread ${thread.id}:`, error); | ||||||
| // Process threads with controlled concurrency to avoid rate limits | ||||||
| const threadIds = result.threads.map((thread) => thread.id); | ||||||
| const syncEffects = threadIds.map(syncSingleThread); | ||||||
|
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. Rule violated: Detect Typescript Performance Bottlenecks Prompt for AI agents |
||||||
|
|
||||||
| yield* Effect.all(syncEffects, { concurrency: 1, discard: true }); | ||||||
|
|
||||||
| totalSynced += result.threads.length; | ||||||
| pageToken = result.nextPageToken; | ||||||
| hasMore = pageToken !== null && shouldLoop; | ||||||
| } | ||||||
|
|
||||||
| // // Broadcast progress after each thread | ||||||
| // this.agent.broadcastChatMessage({ | ||||||
| // type: OutgoingMessageType.Mail_List, | ||||||
| // folder, | ||||||
| // }); | ||||||
| } | ||||||
| return { synced: totalSynced }; | ||||||
| }.bind(this), | ||||||
| ); | ||||||
|
|
||||||
| return { synced: totalSynced }; | ||||||
| try { | ||||||
| const result = await Effect.runPromise( | ||||||
| syncProgram.pipe( | ||||||
| Effect.ensuring( | ||||||
| Effect.sync(() => { | ||||||
| console.log('Setting isSyncing to false'); | ||||||
| this.foldersInSync.delete(folder); | ||||||
| this.agent?.broadcastChatMessage({ | ||||||
| type: OutgoingMessageType.Mail_List, | ||||||
| folder, | ||||||
| }); | ||||||
| }), | ||||||
| ), | ||||||
| ), | ||||||
| ); | ||||||
| return result; | ||||||
| } catch (error) { | ||||||
| console.error('Failed to sync inbox threads:', error); | ||||||
| throw error; | ||||||
| } finally { | ||||||
| console.log('Setting isSyncing to false'); | ||||||
| this.foldersInSync.delete(folder); | ||||||
| if (this.agent) | ||||||
| this.agent.broadcastChatMessage({ | ||||||
| type: OutgoingMessageType.Mail_List, | ||||||
| folder, | ||||||
| }); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
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.
Remove unused import.
The
parseISOimport from 'date-fns' is not used anywhere in the code and should be removed to clean up the imports.-import { parseISO } from 'date-fns';📝 Committable suggestion
🧰 Tools
🪛 GitHub Actions: autofix.ci
[warning] 54-54: ESLint (no-unused-vars): Identifier 'parseISO' is imported but never used. Consider removing this import.
🤖 Prompt for AI Agents