-
Notifications
You must be signed in to change notification settings - Fork 83
[Migration Tool] Implement AI enhancement feature for migration tools #1667
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
716960d
87299fb
2657e5d
463f59e
0754f60
62727ec
08d1607
6a71be3
6ad8f44
33fe8a4
d38e8a3
447e088
c9e911b
0f812c4
059485d
859519c
6a86eb0
50890d1
a6fa6ad
06bae71
c490abb
145ee13
8a58817
0455ade
beabd75
bb74cd0
b1fa459
9bcb076
bb8ca3a
d41bc0a
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 |
|---|---|---|
|
|
@@ -157,6 +157,9 @@ async function determineAffectedPackages( | |
| * - Plan approval workflow (via ApprovalManager in TaskWrite tool) | ||
| */ | ||
| export class AgentExecutor extends AICommandExecutor<GenerateAgentCodeRequest> { | ||
| /** Tracks in-flight tool-call start times keyed by toolCallId for duration logging. */ | ||
| private readonly _pendingToolCalls = new Map<string, number>(); | ||
|
|
||
| constructor(config: AICommandConfig<GenerateAgentCodeRequest>) { | ||
| super(config); | ||
| } | ||
|
|
@@ -253,6 +256,11 @@ export class AgentExecutor extends AICommandExecutor<GenerateAgentCodeRequest> { | |
| }, | ||
| ]; | ||
|
|
||
| // Resolve model and limits | ||
| const llmModel = this.config.model ?? await getAnthropicClient(ANTHROPIC_SONNET_4); | ||
| const maxSteps = this.config.agentLimits?.maxSteps ?? 50; | ||
| const maxOutputTokens = this.config.agentLimits?.maxOutputTokens ?? 8192; | ||
|
|
||
| // Create tools | ||
| const tools = createToolRegistry({ | ||
| eventHandler: this.config.eventHandler, | ||
|
|
@@ -264,6 +272,7 @@ export class AgentExecutor extends AICommandExecutor<GenerateAgentCodeRequest> { | |
| projectRootPath: this.config.executionContext.workspacePath || this.config.executionContext.projectPath || '', | ||
| generationId: this.config.generationId, | ||
| threadId: 'default', | ||
| migrationSourcePath: this.config.toolOptions?.migrationSourcePath, | ||
|
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. Avoid writing raw tool payloads into the debug transcript. The new 🔒 Suggested fix- const raw = typeof rawResult === "string"
- ? rawResult
- : rawResult === undefined
- ? "<no result>"
- : JSON.stringify(rawResult) ?? "<no result>";
- this.config.debugLogger.logToolCall((part as any).toolName, durationMs, raw);
+ const resultSummary =
+ rawResult === undefined
+ ? "<no result>"
+ : typeof rawResult === "string"
+ ? `<string:${rawResult.length} chars>`
+ : Array.isArray(rawResult)
+ ? `<array:${rawResult.length} items>`
+ : rawResult && typeof rawResult === "object"
+ ? `<object:${Object.keys(rawResult).length} keys>`
+ : String(rawResult);
+ this.config.debugLogger.logToolCall((part as any).toolName, durationMs, resultSummary);Also applies to: 569-580 🤖 Prompt for AI Agents |
||
| runningServices: runningServicesManager, | ||
| webSearchEnabled: params.webSearchEnabled ?? false, | ||
| ctx: this.config.executionContext, | ||
|
|
@@ -455,6 +464,14 @@ Generation stopped by user. The last in-progress task was not saved. Files have | |
| } | ||
| ); | ||
|
|
||
| // Notify caller with partial messages (wizard migration history persistence) | ||
| if (this.config.onMessagesAvailable) { | ||
| this.config.onMessagesAvailable( | ||
| [{ role: "user", content: streamContext.userMessageContent }, ...partialLLMMessages], | ||
| 'aborted' | ||
| ); | ||
| } | ||
|
Comment on lines
+467
to
+473
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. Call This hook is only fired from the abort branch. If the wizard depends on it to persist migration history, completed runs and hard failures will never be saved or resumed. 🧩 Suggested follow-up// handleStreamFinish(...)
this.config.onMessagesAvailable?.(
[{ role: "user", content: context.userMessageContent }, ...assistantMessages],
"completed"
);
// handleStreamError(...)
this.config.onMessagesAvailable?.(
[{ role: "user", content: context.userMessageContent }, ...messagesToSave],
"error"
);🤖 Prompt for AI Agents |
||
|
|
||
| // Note: Abort event is sent by base class handleExecutionError() | ||
| } | ||
|
|
||
|
|
@@ -487,9 +504,17 @@ Generation stopped by user. The last in-progress task was not saved. Files have | |
| throw error; | ||
| } | ||
|
|
||
| console.error("[AgentExecutor] Non-abort error in execute():", error); | ||
|
|
||
| // Abort the controller so that any in-flight tool executions | ||
| // managed by the AI SDK are cancelled and stop emitting events. | ||
| if (!this.config.abortController.signal.aborted) { | ||
| this.config.abortController.abort(); | ||
| } | ||
|
|
||
| this.config.eventHandler({ | ||
| type: "error", | ||
| content: "An error occurred during agent execution. Please check the logs for details." | ||
| content: getErrorMessage(error) | ||
| }); | ||
|
|
||
| // For other errors, return result with error | ||
|
|
@@ -535,8 +560,31 @@ Generation stopped by user. The last in-progress task was not saved. Files have | |
| await this.handleStreamFinish(context); | ||
| break; | ||
|
|
||
| case "tool-call": | ||
| if (this.config.debugLogger) { | ||
| this._pendingToolCalls.set((part as any).toolCallId, Date.now()); | ||
| } | ||
| break; | ||
|
|
||
| case "tool-result": | ||
| if (this.config.debugLogger) { | ||
| const startMs = this._pendingToolCalls.get((part as any).toolCallId); | ||
| if (startMs !== undefined) { | ||
| const durationMs = Date.now() - startMs; | ||
| const rawResult = (part as any).result; | ||
| const raw = typeof rawResult === "string" | ||
| ? rawResult | ||
| : rawResult === undefined | ||
| ? "<no result>" | ||
| : JSON.stringify(rawResult) ?? "<no result>"; | ||
| this.config.debugLogger.logToolCall((part as any).toolName, durationMs, raw); | ||
| this._pendingToolCalls.delete((part as any).toolCallId); | ||
| } | ||
| } | ||
| break; | ||
|
|
||
| default: | ||
| // Tool calls/results handled automatically by SDK | ||
| // All other stream part types (step-finish, etc.) are handled by the SDK. | ||
| break; | ||
| } | ||
| } | ||
|
|
@@ -682,27 +730,36 @@ Generation stopped by user. The last in-progress task was not saved. Files have | |
| // Update chat state storage | ||
| await this.updateChatState(context, assistantMessages, tempProjectPath); | ||
|
|
||
| // Integrate generated code into workspace immediately so user sees changes during review | ||
| const workspaceId = context.ctx.workspacePath || context.ctx.projectPath; | ||
| const pendingReview = chatStateStorage.getPendingReviewGeneration(workspaceId, 'default'); | ||
| if (pendingReview && pendingReview.reviewState.modifiedFiles.length > 0) { | ||
| const integrationCtx = { ...context.ctx }; | ||
| // In workspace mode, resolve project path from modified files if not set | ||
| if (!integrationCtx.projectPath && integrationCtx.workspacePath && pendingReview.reviewState.modifiedFiles.length > 0) { | ||
| const firstBalFile = pendingReview.reviewState.modifiedFiles.find(f => f.endsWith('.bal')); | ||
| if (firstBalFile) { | ||
| const packageName = firstBalFile.split('/')[0]; | ||
| if (packageName) { | ||
| integrationCtx.projectPath = path.join(integrationCtx.workspacePath, packageName); | ||
| StateMachine.context().projectPath = integrationCtx.projectPath; | ||
| // Integrate generated code into workspace immediately so user sees changes during review. | ||
| // Skip only when the temp path IS the real workspace directory (migration wizard in-place | ||
| // editing). A review-continuation run also sets existingTempPath but to a temp dir, so we | ||
| // compare resolved paths rather than just checking existingTempPath presence. | ||
| const workspaceRoot = context.ctx.workspacePath || context.ctx.projectPath; | ||
| const isInPlaceEditing = | ||
| !!workspaceRoot && | ||
| path.resolve(tempProjectPath) === path.resolve(workspaceRoot); | ||
| if (!isInPlaceEditing) { | ||
| const workspaceId = workspaceRoot; | ||
| const pendingReview = chatStateStorage.getPendingReviewGeneration(workspaceId, 'default'); | ||
| if (pendingReview && pendingReview.reviewState.modifiedFiles.length > 0) { | ||
| const integrationCtx = { ...context.ctx }; | ||
| // In workspace mode, resolve project path from modified files if not set | ||
| if (!integrationCtx.projectPath && integrationCtx.workspacePath && pendingReview.reviewState.modifiedFiles.length > 0) { | ||
| const firstBalFile = pendingReview.reviewState.modifiedFiles.find(f => f.endsWith('.bal')); | ||
| if (firstBalFile) { | ||
| const packageName = firstBalFile.split('/')[0]; | ||
| if (packageName) { | ||
| integrationCtx.projectPath = path.join(integrationCtx.workspacePath, packageName); | ||
| StateMachine.context().projectPath = integrationCtx.projectPath; | ||
| } | ||
| } | ||
| } | ||
| await integrateCodeToWorkspace( | ||
| pendingReview.reviewState.tempProjectPath!, | ||
| new Set(pendingReview.reviewState.modifiedFiles), | ||
| integrationCtx | ||
| ); | ||
| } | ||
| await integrateCodeToWorkspace( | ||
| pendingReview.reviewState.tempProjectPath!, | ||
| new Set(pendingReview.reviewState.modifiedFiles), | ||
| integrationCtx | ||
| ); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| // Emit UI events | ||
|
|
||
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.
Apply the resolved model and limit overrides to the live agent loop.
llmModel,maxSteps, andmaxOutputTokensare computed here, but the stream still runs with the defaultmodel,8192, andstepCountIs(50). Any migration execution that passes a different model or larger limits will be silently ignored during the main agent loop.🛠️ Proposed fix
Also applies to: 310-325, 372-372
🤖 Prompt for AI Agents