Repository navigation
Expand file tree
/
Copy pathuser_request_use_case.ts
More file actions
136 lines (119 loc) · 5.16 KB
/
Copy pathuser_request_use_case.ts
File metadata and controls
136 lines (119 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* Use case that performs whatever changes the user asked for (generic request).
* Uses the configured build agent to edit files and run commands in the workspace.
* Caller is responsible for permission check and for running commit/push after success.
*/
import { isAgentConfigurationReady } from "../../../../data/model/agent";
import type { FixerQueryPort } from "../../../ports/agent_fixer_ports";
import { getUserRequestPrompt } from "../../../../prompts";
import { logDebugInfo, logError, logInfo } from "../../../ports/logging_ports";
import { getTaskEmoji } from "../../../../utils/task_emoji";
import { ParamUseCase } from "../../base/param_usecase";
import { Result } from "../../../../data/model/result";
import { PROJECT_CONTEXT_INSTRUCTION } from "../../../../utils/project_context_instruction";
import { sanitizeUserCommentForPrompt } from "./bugbot/sanitize_user_comment_for_prompt";
import type { BugbotGitMutationPort } from '../../../ports/bugbot_git_ports';
import type { UserRequestContext } from '../../push_single_action_contexts';
import { finalizeWorkspaceMutation, prepareWorkspaceMutation } from './workspace_mutation_guard';
import { ApplicationError, toApplicationError } from '../../../errors/application_error';
const TASK_ID = "DoUserRequestUseCase";
export interface DoUserRequestParam {
context: UserRequestContext;
userComment: string;
branchOverride?: string;
}
export class DoUserRequestUseCase implements ParamUseCase<DoUserRequestParam, Result[]> {
taskId: string = TASK_ID;
constructor(
private readonly aiRepository: FixerQueryPort,
private readonly gitCommitPort: BugbotGitMutationPort,
) {}
async invoke(param: DoUserRequestParam): Promise<Result[]> {
logInfo(`${getTaskEmoji(this.taskId)} Executing ${this.taskId}.`);
const results: Result[] = [];
const { context, userComment } = param;
if (!isAgentConfigurationReady(context.agentConfiguration)) {
logInfo("Agent not configured; skipping user request.");
return results;
}
const commentTrimmed = userComment?.trim() ?? "";
if (!commentTrimmed) {
logInfo("No user comment; skipping user request.");
return results;
}
const targetBranch = param.branchOverride ?? context.headBranch;
if (!targetBranch?.trim()) {
return [failure(new ApplicationError('workflow.invalid-event',
'User-request implementation requires an authoritative branch; a general conversation cannot infer one.'))];
}
let mutation;
try {
mutation = await prepareWorkspaceMutation(this.gitCommitPort, {
operation: 'User-request implementation',
branch: targetBranch,
});
} catch (error) {
return [failure(error)];
}
const prompt = getUserRequestPrompt({
projectContextInstruction: PROJECT_CONTEXT_INSTRUCTION,
owner: context.repository.owner,
repo: context.repository.name,
headBranch: targetBranch,
baseBranch: context.baseBranch,
issueNumber: String(context.issueNumber),
userComment: sanitizeUserCommentForPrompt(userComment),
});
logDebugInfo(`DoUserRequest: prompt length=${prompt.length}, user comment length=${commentTrimmed.length}.`);
logInfo("Running configured build agent to perform user request (changes applied in workspace).");
const response = await this.aiRepository.fix({
configuration: context.agentConfiguration,
prompt,
});
logDebugInfo(`DoUserRequest: build agent response length=${response?.text?.length ?? 0}.`);
if (!response?.text) {
logError("DoUserRequest: no response from configured build agent.");
results.push(
new Result({
id: this.taskId,
success: false,
executed: true,
errors: [new ApplicationError('agent.failed', "Configured build agent returned no response.")],
})
);
return results;
}
let workspacePaths: string[];
try {
({ workspacePaths } = await finalizeWorkspaceMutation(
this.gitCommitPort,
mutation.workspacePathsBefore,
'User-request implementation',
));
} catch (error) {
return [failure(error)];
}
results.push(new Result({
id: this.taskId,
success: true,
executed: true,
steps: [],
payload: {
branchOverride: param.branchOverride,
branchCheckedOut: mutation.branchCheckedOut,
workspacePaths,
},
}));
return results;
}
}
function failure(error: unknown): Result {
const semanticError = toApplicationError(error, 'workflow.failed', 'User-request implementation failed.');
logError(semanticError);
return new Result({
id: TASK_ID,
success: false,
executed: true,
errors: [semanticError],
});
}