Skip to content

Commit e0f79c9

Browse files
committed
feature-233-implement-openrouter: Enhance CLI and action handling for AI interactions
- Updated CLI to include new options for OpenRouter configuration and improved command descriptions. - Refactored action handling to support new parameters for AI interactions, including welcome messages and reasoning options. - Introduced a new method in SupabaseRepository for duplicating chunks between branches. - Enhanced logging for better tracking of AI interactions and processing steps. - Removed deprecated AskActionUseCase to streamline AI query handling.
1 parent 3a10e4c commit e0f79c9

15 files changed

Lines changed: 200 additions & 101 deletions

src/actions/common_action.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { PullRequestReviewCommentUseCase } from '../usecase/pull_request_review_
88
import { PullRequestUseCase } from '../usecase/pull_request_use_case';
99
import { SingleActionUseCase } from '../usecase/single_action_use_case';
1010
import { logInfo } from '../utils/logger';
11+
import { TITLE } from '../utils/constants';
12+
import chalk from 'chalk';
13+
import boxen from 'boxen';
1114

1215
export async function mainRun(execution: Execution): Promise<Result[]> {
1316
await execution.setup();
@@ -22,6 +25,23 @@ export async function mainRun(execution: Execution): Promise<Result[]> {
2225
return [];
2326
}
2427

28+
if (execution.welcome) {
29+
logInfo(
30+
boxen(
31+
chalk.cyan(execution.welcome.title) +
32+
execution.welcome.messages.map(message => chalk.gray(message)).join('\n'),
33+
{
34+
padding: 1,
35+
margin: 1,
36+
borderStyle: 'round',
37+
borderColor: 'cyan',
38+
title: TITLE,
39+
titleAlignment: 'center'
40+
}
41+
)
42+
);
43+
}
44+
2545
const results: Result[] = []
2646

2747
try {

src/actions/github_action.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ export async function runGitHubAction(): Promise<void> {
3535
*/
3636
const debug = core.getInput(INPUT_KEYS.DEBUG) == 'true'
3737

38+
/**
39+
* Docker
40+
*/
3841
const dockerContainerName = core.getInput(INPUT_KEYS.DOCKER_CONTAINER_NAME);
3942
const dockerDomain = core.getInput(INPUT_KEYS.DOCKER_DOMAIN);
4043
const dockerPort = parseInt(core.getInput(INPUT_KEYS.DOCKER_PORT));
@@ -57,6 +60,7 @@ export async function runGitHubAction(): Promise<void> {
5760
const openrouterModel = core.getInput(INPUT_KEYS.OPENROUTER_MODEL)
5861
const aiPullRequestDescription = core.getInput(INPUT_KEYS.AI_PULL_REQUEST_DESCRIPTION) === 'true';
5962
const aiMembersOnly = core.getInput(INPUT_KEYS.AI_MEMBERS_ONLY) === 'true';
63+
const aiIncludeReasoning = core.getInput(INPUT_KEYS.AI_INCLUDE_REASONING) === 'true';
6064
const aiIgnoreFilesInput: string = core.getInput(INPUT_KEYS.AI_IGNORE_FILES);
6165
const aiIgnoreFiles: string[] = aiIgnoreFilesInput
6266
.split(',')
@@ -512,6 +516,7 @@ export async function runGitHubAction(): Promise<void> {
512516
aiPullRequestDescription,
513517
aiMembersOnly,
514518
aiIgnoreFiles,
519+
aiIncludeReasoning,
515520
Object.keys(providerRouting).length > 0 ? providerRouting : undefined
516521
),
517522
new Labels(
@@ -610,6 +615,7 @@ export async function runGitHubAction(): Promise<void> {
610615
),
611616
new SupabaseConfig(supabaseUrl, supabaseKey),
612617
undefined,
618+
undefined,
613619
)
614620

615621
const results: Result[] = await mainRun(execution);

src/actions/local_action.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { SizeThreshold } from '../data/model/size_threshold';
1818
import { SizeThresholds } from '../data/model/size_thresholds';
1919
import { SupabaseConfig } from '../data/model/supabase_config';
2020
import { Tokens } from '../data/model/tokens';
21+
import { Welcome } from '../data/model/welcome';
2122
import { Workflows } from '../data/model/workflows';
2223
import { ProjectRepository } from '../data/repository/project_repository';
2324
import { DEFAULT_IMAGE_CONFIG, INPUT_KEYS } from '../utils/constants';
@@ -35,6 +36,12 @@ export async function runLocalAction(additionalParams: any): Promise<void> {
3536
*/
3637
const debug = (additionalParams[INPUT_KEYS.DEBUG] ?? actionInputs[INPUT_KEYS.DEBUG]) == 'true'
3738

39+
/**
40+
* Welcome
41+
*/
42+
const welcomeTitle = additionalParams[INPUT_KEYS.WELCOME_TITLE] ?? actionInputs[INPUT_KEYS.WELCOME_TITLE];
43+
const welcomeMessages = additionalParams[INPUT_KEYS.WELCOME_MESSAGES] ?? actionInputs[INPUT_KEYS.WELCOME_MESSAGES];
44+
3845
/**
3946
* Docker
4047
*/
@@ -60,6 +67,7 @@ export async function runLocalAction(additionalParams: any): Promise<void> {
6067
const openrouterModel = additionalParams[INPUT_KEYS.OPENROUTER_MODEL] ?? actionInputs[INPUT_KEYS.OPENROUTER_MODEL];
6168
const aiPullRequestDescription = (additionalParams[INPUT_KEYS.AI_PULL_REQUEST_DESCRIPTION] ?? actionInputs[INPUT_KEYS.AI_PULL_REQUEST_DESCRIPTION]) === 'true';
6269
const aiMembersOnly = (additionalParams[INPUT_KEYS.AI_MEMBERS_ONLY] ?? actionInputs[INPUT_KEYS.AI_MEMBERS_ONLY]) === 'true';
70+
const aiIncludeReasoning = (additionalParams[INPUT_KEYS.AI_INCLUDE_REASONING] ?? actionInputs[INPUT_KEYS.AI_INCLUDE_REASONING]) === 'true';
6371
const aiIgnoreFilesInput: string = additionalParams[INPUT_KEYS.AI_IGNORE_FILES] ?? actionInputs[INPUT_KEYS.AI_IGNORE_FILES];
6472
const aiIgnoreFiles: string[] = aiIgnoreFilesInput
6573
.split(',')
@@ -517,6 +525,7 @@ export async function runLocalAction(additionalParams: any): Promise<void> {
517525
aiPullRequestDescription,
518526
aiMembersOnly,
519527
aiIgnoreFiles,
528+
aiIncludeReasoning,
520529
Object.keys(providerRouting).length > 0 ? providerRouting : undefined
521530
),
522531
new Labels(
@@ -614,6 +623,7 @@ export async function runLocalAction(additionalParams: any): Promise<void> {
614623
projectColumnPullRequestInProgress,
615624
),
616625
new SupabaseConfig(supabaseUrl, supabaseKey),
626+
new Welcome(welcomeTitle, welcomeMessages),
617627
additionalParams,
618628
)
619629

src/cli.ts

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ program
5454
return;
5555
}
5656

57-
const params = {
57+
const params: any = {
5858
[INPUT_KEYS.DEBUG]: options.debug.toString(),
5959
[INPUT_KEYS.SINGLE_ACTION]: ACTIONS.VECTOR,
6060
[INPUT_KEYS.SINGLE_ACTION_ISSUE]: options.issue,
@@ -74,38 +74,38 @@ program
7474
},
7575
}
7676

77-
logInfo(
78-
boxen(
79-
chalk.cyan('🚀 Vectorization started\n') +
80-
chalk.gray(`Processing code blocks on ${gitInfo.owner}/${gitInfo.repo}/${options.branch}...`),
81-
{
82-
padding: 1,
83-
margin: 1,
84-
borderStyle: 'round',
85-
borderColor: 'cyan',
86-
title: TITLE,
87-
titleAlignment: 'center'
88-
}
89-
)
90-
);
77+
params[INPUT_KEYS.WELCOME_TITLE] = '🚀 Vectorization started';
78+
params[INPUT_KEYS.WELCOME_MESSAGES] = [
79+
`Processing code blocks on ${gitInfo.owner}/${gitInfo.repo}/${options.branch}...`,
80+
];
9181

9282
runLocalAction(params);
9383
});
9484

85+
/**
86+
* Run the asking AI scenario on issues or pull requests.
87+
*
88+
* For the action of asking the AI to be executed, the bot user managing the repository must be mentioned.
89+
*/
9590
program
9691
.command('ask-ai')
9792
.description('Ask AI')
9893
.option('-i, --issue <number>', 'Issue number to process', '1')
9994
.option('-b, --branch <name>', 'Branch name', 'master')
10095
.option('-d, --debug', 'Debug mode', false)
10196
.option('-t, --token <token>', 'Personal access token', process.env.PERSONAL_ACCESS_TOKEN)
102-
.option('-m, --model <model>', 'OpenRouter model', process.env.OPENROUTER_MODEL)
103-
.option('-k, --key <key>', 'OpenRouter API key', process.env.OPENROUTER_API_KEY)
104-
.option('-p, --provider <provider>', 'OpenRouter provider', process.env.OPENROUTER_PROVIDER_ORDER)
105-
.option('-f, --fallback <fallback>', 'OpenRouter fallback', process.env.OPENROUTER_PROVIDER_ALLOW_FALLBACKS)
106-
.option('-r, --require <require>', 'OpenRouter require', process.env.OPENROUTER_PROVIDER_REQUIRE_PARAMETERS)
107-
.option('-c, --collection <collection>', 'OpenRouter collection', process.env.OPENROUTER_PROVIDER_DATA_COLLECTION)
108-
.option('-q, --question <question>', 'Question', '')
97+
.option('--question <question>', 'Question', '')
98+
.option('--openrouter-api-key <key>', 'OpenRouter API key', '')
99+
.option('--openrouter-model <model>', 'OpenRouter model', '')
100+
.option('--openrouter-provider-order <provider>', 'OpenRouter provider', '')
101+
.option('--openrouter-provider-allow-fallbacks <fallback>', 'OpenRouter fallback', '')
102+
.option('--openrouter-provider-require-parameters <require>', 'OpenRouter require', '')
103+
.option('--openrouter-provider-data-collection <collection>', 'OpenRouter collection', '')
104+
.option('--openrouter-provider-ignore <ignore>', 'OpenRouter ignore', '')
105+
.option('--openrouter-provider-quantizations <quantizations>', 'OpenRouter quantizations', '')
106+
.option('--openrouter-provider-sort <sort>', 'OpenRouter sort', '')
107+
.option('--ai-ignore-files <ai-ignore-files>', 'AI ignore files', 'dist/*,bin/*,node_modules/*,build/*')
108+
.option('--include-reasoning <include-reasoning>', 'Include reasoning', 'false')
109109
.action(async (options) => {
110110
const gitInfo = getGitInfo();
111111

@@ -118,18 +118,20 @@ program
118118

119119
const params: any = {
120120
[INPUT_KEYS.DEBUG]: options.debug.toString(),
121-
[INPUT_KEYS.SINGLE_ACTION]: ACTIONS.ASK,
122-
[INPUT_KEYS.SINGLE_ACTION_ISSUE]: options.issue,
123-
[INPUT_KEYS.SUPABASE_URL]: process.env.SUPABASE_URL,
124-
[INPUT_KEYS.SUPABASE_KEY]: process.env.SUPABASE_KEY,
125-
[INPUT_KEYS.TOKEN]: process.env.PERSONAL_ACCESS_TOKEN,
126-
[INPUT_KEYS.OPENROUTER_API_KEY]: process.env.OPENROUTER_API_KEY,
127-
[INPUT_KEYS.OPENROUTER_MODEL]: process.env.OPENROUTER_MODEL,
128-
[INPUT_KEYS.OPENROUTER_PROVIDER_ORDER]: process.env.OPENROUTER_PROVIDER_ORDER,
129-
[INPUT_KEYS.OPENROUTER_PROVIDER_ALLOW_FALLBACKS]: process.env.OPENROUTER_PROVIDER_ALLOW_FALLBACKS,
130-
[INPUT_KEYS.OPENROUTER_PROVIDER_REQUIRE_PARAMETERS]: process.env.OPENROUTER_PROVIDER_REQUIRE_PARAMETERS,
131-
[INPUT_KEYS.OPENROUTER_PROVIDER_DATA_COLLECTION]: process.env.OPENROUTER_PROVIDER_DATA_COLLECTION,
132-
[INPUT_KEYS.AI_IGNORE_FILES]: 'dist/*,bin/*',
121+
[INPUT_KEYS.SUPABASE_URL]: options.supabaseUrl.length > 0 ? options.supabaseUrl : process.env.SUPABASE_URL,
122+
[INPUT_KEYS.SUPABASE_KEY]: options.supabaseKey.length > 0 ? options.supabaseKey : process.env.SUPABASE_KEY,
123+
[INPUT_KEYS.TOKEN]: options.token.length > 0 ? options.token : process.env.PERSONAL_ACCESS_TOKEN,
124+
[INPUT_KEYS.OPENROUTER_API_KEY]: options.openrouterApiKey.length > 0 ? options.openrouterApiKey : process.env.OPENROUTER_API_KEY,
125+
[INPUT_KEYS.OPENROUTER_MODEL]: options.openrouterModel.length > 0 ? options.openrouterModel : process.env.OPENROUTER_MODEL,
126+
[INPUT_KEYS.OPENROUTER_PROVIDER_ORDER]: options.openrouterProviderOrder.length > 0 ? options.openrouterProviderOrder : process.env.OPENROUTER_PROVIDER_ORDER,
127+
[INPUT_KEYS.OPENROUTER_PROVIDER_ALLOW_FALLBACKS]: options.openrouterProviderAllowFallbacks.length > 0 ? options.openrouterProviderAllowFallbacks : process.env.OPENROUTER_PROVIDER_ALLOW_FALLBACKS,
128+
[INPUT_KEYS.OPENROUTER_PROVIDER_REQUIRE_PARAMETERS]: options.openrouterProviderRequireParameters.length > 0 ? options.openrouterProviderRequireParameters : process.env.OPENROUTER_PROVIDER_REQUIRE_PARAMETERS,
129+
[INPUT_KEYS.OPENROUTER_PROVIDER_DATA_COLLECTION]: options.openrouterProviderDataCollection.length > 0 ? options.openrouterProviderDataCollection : process.env.OPENROUTER_PROVIDER_DATA_COLLECTION,
130+
[INPUT_KEYS.OPENROUTER_PROVIDER_IGNORE]: options.openrouterProviderIgnore.length > 0 ? options.openrouterProviderIgnore : process.env.OPENROUTER_PROVIDER_IGNORE,
131+
[INPUT_KEYS.OPENROUTER_PROVIDER_QUANTIZATIONS]: options.openrouterProviderQuantizations.length > 0 ? options.openrouterProviderQuantizations : process.env.OPENROUTER_PROVIDER_QUANTIZATIONS,
132+
[INPUT_KEYS.OPENROUTER_PROVIDER_SORT]: options.openrouterProviderSort.length > 0 ? options.openrouterProviderSort : process.env.OPENROUTER_PROVIDER_SORT,
133+
[INPUT_KEYS.AI_IGNORE_FILES]: options.aiIgnoreFiles.length > 0 ? options.aiIgnoreFiles : process.env.AI_IGNORE_FILES,
134+
[INPUT_KEYS.AI_INCLUDE_REASONING]: options.includeReasoning.length > 0 ? options.includeReasoning : process.env.AI_INCLUDE_REASONING,
133135
repo: {
134136
owner: gitInfo.owner,
135137
repo: gitInfo.repo,
@@ -144,14 +146,14 @@ program
144146
gitInfo.owner,
145147
gitInfo.repo,
146148
parseInt(options.issue),
147-
process.env.PERSONAL_ACCESS_TOKEN ?? ''
149+
params[INPUT_KEYS.TOKEN] ?? ''
148150
);
149151

150152
const isPullRequest = await issueRepository.isPullRequest(
151153
gitInfo.owner,
152154
gitInfo.repo,
153155
parseInt(options.issue),
154-
process.env.PERSONAL_ACCESS_TOKEN ?? ''
156+
params[INPUT_KEYS.TOKEN] ?? ''
155157
);
156158

157159
if (isIssue) {
@@ -164,28 +166,18 @@ program
164166
}
165167
} else if (isPullRequest) {
166168
params.eventName = 'pull_request_review_comment';
167-
params.issue = {
169+
params.pull_request = {
168170
number: parseInt(options.issue),
169171
}
170172
params.pull_request_review_comment = {
171173
body: commentBody,
172174
}
173175
}
174176

175-
logInfo(
176-
boxen(
177-
chalk.cyan('🚀 Asking AI started\n') +
178-
chalk.gray(`Asking AI on ${gitInfo.owner}/${gitInfo.repo}/${options.branch}...`),
179-
{
180-
padding: 1,
181-
margin: 1,
182-
borderStyle: 'round',
183-
borderColor: 'cyan',
184-
title: TITLE,
185-
titleAlignment: 'center'
186-
}
187-
)
188-
);
177+
params[INPUT_KEYS.WELCOME_TITLE] = '🚀 Asking AI started';
178+
params[INPUT_KEYS.WELCOME_MESSAGES] = [
179+
`Asking AI on ${gitInfo.owner}/${gitInfo.repo}/${options.branch}...`,
180+
];
189181

190182
runLocalAction(params);
191183
});

src/data/model/ai.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class Ai {
1414
private aiPullRequestDescription: boolean;
1515
private aiMembersOnly: boolean;
1616
private aiIgnoreFiles: string[];
17+
private aiIncludeReasoning: boolean;
1718
private providerRouting: ProviderRoutingConfig;
1819

1920
constructor(
@@ -22,13 +23,15 @@ export class Ai {
2223
aiPullRequestDescription: boolean,
2324
aiMembersOnly: boolean,
2425
aiIgnoreFiles: string[],
26+
aiIncludeReasoning: boolean,
2527
providerRouting?: ProviderRoutingConfig
2628
) {
2729
this.openRouterApiKey = openRouterApiKey;
2830
this.openRouterModel = openRouterModel;
2931
this.aiPullRequestDescription = aiPullRequestDescription;
3032
this.aiMembersOnly = aiMembersOnly;
3133
this.aiIgnoreFiles = aiIgnoreFiles;
34+
this.aiIncludeReasoning = aiIncludeReasoning;
3235
this.providerRouting = providerRouting || {};
3336
}
3437

@@ -48,6 +51,10 @@ export class Ai {
4851
return this.aiIgnoreFiles;
4952
}
5053

54+
getAiIncludeReasoning(): boolean {
55+
return this.aiIncludeReasoning;
56+
}
57+
5158
getOpenRouterModel(): string {
5259
return this.openRouterModel;
5360
}

src/data/model/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {Result} from "./result";
44
export class Config {
55
branchType: string;
66
releaseBranch: string | undefined;
7+
workingBranch: string | undefined;
78
parentBranch: string | undefined;
89
hotfixOriginBranch: string | undefined;
910
hotfixBranch: string | undefined;
@@ -16,6 +17,7 @@ export class Config {
1617
this.hotfixBranch = data['hotfixBranch'];
1718
this.releaseBranch = data['releaseBranch'];
1819
this.parentBranch = data['parentBranch'];
20+
this.workingBranch = data['workingBranch'];
1921
if (data['branchConfiguration'] !== undefined) {
2022
this.branchConfiguration = new BranchConfiguration(data['branchConfiguration']);
2123
}

src/data/model/execution.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ConfigurationHandler } from "../../manager/description/configuration_ha
44
import { GetHotfixVersionUseCase } from "../../usecase/steps/common/get_hotfix_version_use_case";
55
import { GetReleaseTypeUseCase } from "../../usecase/steps/common/get_release_type_use_case";
66
import { GetReleaseVersionUseCase } from "../../usecase/steps/common/get_release_version_use_case";
7+
import { INPUT_KEYS } from "../../utils/constants";
78
import { branchesForManagement, typesForIssue } from "../../utils/label_utils";
89
import { logDebugInfo, setGlobalLoggerDebug } from "../../utils/logger";
910
import { extractIssueNumberFromBranch, extractIssueNumberFromPush } from "../../utils/title_utils";
@@ -13,29 +14,29 @@ import { IssueRepository } from "../repository/issue_repository";
1314
import { ProjectRepository } from "../repository/project_repository";
1415
import { Ai } from "./ai";
1516
import { Branches } from "./branches";
17+
import { Commit } from "./commit";
18+
import { Config } from "./config";
19+
import { DockerConfig } from "./docker_config";
1620
import { Emoji } from "./emoji";
1721
import { Hotfix } from "./hotfix";
1822
import { Images } from "./images";
1923
import { Issue } from "./issue";
2024
import { IssueTypes } from "./issue_types";
2125
import { Labels } from "./labels";
26+
import { Locale } from "./locale";
2227
import { Projects } from "./projects";
2328
import { PullRequest } from "./pull_request";
2429
import { Release } from "./release";
2530
import { SingleAction } from "./single_action";
2631
import { SizeThresholds } from "./size_thresholds";
32+
import { SupabaseConfig } from "./supabase_config";
2733
import { Tokens } from "./tokens";
34+
import { Welcome } from "./welcome";
2835
import { Workflows } from "./workflows";
29-
import { Locale } from "./locale";
30-
import { SupabaseConfig } from "./supabase_config";
31-
import { DockerConfig } from "./docker_config";
32-
import { Config } from "./config";
33-
import { Commit } from "./commit";
34-
import { INPUT_KEYS } from "../../utils/constants";
3536

3637
export class Execution {
3738
debug: boolean = false;
38-
39+
welcome: Welcome | undefined;
3940
/**
4041
* Every usage of this field should be checked.
4142
* PRs with no issue ID in the head branch won't have it.
@@ -195,6 +196,7 @@ export class Execution {
195196
workflows: Workflows,
196197
project: Projects,
197198
supabaseConfig: SupabaseConfig | undefined,
199+
welcome: Welcome | undefined,
198200
inputs: any | undefined
199201
) {
200202
this.debug = debug;
@@ -219,6 +221,7 @@ export class Execution {
219221
this.currentConfiguration = new Config({});
220222
this.supabaseConfig = supabaseConfig;
221223
this.inputs = inputs;
224+
this.welcome = welcome;
222225
}
223226

224227
setup = async () => {

src/data/model/single_action.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { logError } from "../../utils/logger";
44
export class SingleAction {
55
currentSingleAction: string;
66
currentSingleActionIssue: number = -1;
7-
actions: string[] = [ACTIONS.DEPLOYED, ACTIONS.VECTOR, ACTIONS.ASK];
7+
actions: string[] = [ACTIONS.DEPLOYED, ACTIONS.VECTOR];
88
isIssue: boolean = false;
99
isPullRequest: boolean = false;
1010
isPush: boolean = false;
@@ -17,10 +17,6 @@ export class SingleAction {
1717
return this.currentSingleAction === ACTIONS.VECTOR;
1818
}
1919

20-
get isAskAction(): boolean {
21-
return this.currentSingleAction === ACTIONS.ASK;
22-
}
23-
2420
get enabledSingleAction(): boolean {
2521
return this.currentSingleAction.length > 0;
2622
}

0 commit comments

Comments
 (0)