Skip to content

Commit 838ad1a

Browse files
authored
Merge pull request #305 from codefori/fix/continue-context
2 parents e3d4614 + e03b84e commit 838ad1a

File tree

6 files changed

+201
-20
lines changed

6 files changed

+201
-20
lines changed

src/aiProviders/context.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { JobManager } from "../config";
22
import * as vscode from "vscode";
33
import Statement from "../database/statement";
4+
import { ContextItem } from "@continuedev/core";
45

56
export function canTalkToDb() {
67
return JobManager.getSelection() !== undefined;
@@ -99,7 +100,7 @@ export async function findPossibleTables(stream: vscode.ChatResponseStream, sche
99100
*
100101
* Tables with names starting with 'SYS' are skipped.
101102
*/
102-
export function refsToMarkdown(refs: TableRefs) {
103+
export function refsToMarkdown(refs: TableRefs): MarkdownRef[] {
103104
const condensedResult = Object.keys(refs).length > 5;
104105

105106
let markdownRefs: MarkdownRef[] = [];
@@ -122,6 +123,23 @@ export function refsToMarkdown(refs: TableRefs) {
122123
return markdownRefs;
123124
}
124125

126+
export function createContinueContextItems(refs: MarkdownRef[]) {
127+
const contextItems: ContextItem[] = [];
128+
const job = JobManager.getSelection();
129+
for (const tableRef of refs) {
130+
let prompt = `Table: ${tableRef.TABLE_NAME} (Schema: ${tableRef.SCHMEA}) Column Information:\n`;
131+
prompt += `Format: column_name (column_text) type(length:precision) is_identity is_nullable\n`
132+
prompt += `${tableRef.COLUMN_INFO}`;
133+
contextItems.push({
134+
name: `${job.name}-${tableRef.SCHMEA}-${tableRef.TABLE_NAME}`,
135+
description: `Column information for ${tableRef.TABLE_NAME}`,
136+
content: prompt,
137+
});
138+
}
139+
140+
return contextItems;
141+
}
142+
125143
export async function getSystemStatus(): Promise<string> {
126144
const sqlStatment = `SELECT * FROM TABLE(QSYS2.SYSTEM_STATUS(RESET_STATISTICS=>'YES',DETAILED_INFO=>'ALL')) X`;
127145
const result = await JobManager.runSQL(sqlStatment, undefined);

src/aiProviders/continue/continueContextProvider.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as vscode from "vscode";
22
import { JobManager } from "../../config";
33
import { JobInfo } from "../../connection/manager";
44
import { SelfCodeNode } from "../../views/jobManager/selfCodes/nodes";
5-
import { canTalkToDb, findPossibleTables, refsToMarkdown } from "../context";
5+
import { canTalkToDb, createContinueContextItems, findPossibleTables, refsToMarkdown } from "../context";
66
import {
77
ContextItem,
88
ContextProviderDescription,
@@ -146,16 +146,7 @@ export class db2ContextProvider implements IContextProvider {
146146
);
147147
const markdownRefs = refsToMarkdown(tableRefs);
148148

149-
for (const tableRef of markdownRefs) {
150-
let prompt = `Table: ${tableRef.TABLE_NAME} (Schema: ${tableRef.SCHMEA}) Column Information:\n`;
151-
prompt += `Format: column_name (column_text) type(length:precision) is_identity is_nullable\n`
152-
prompt += `${tableRef.COLUMN_INFO}`;
153-
contextItems.push({
154-
name: `${job.name}-${tableRef.SCHMEA}-${tableRef.TABLE_NAME}`,
155-
description: `Column information for ${tableRef.TABLE_NAME}`,
156-
content: prompt,
157-
});
158-
}
149+
contextItems.push(...createContinueContextItems(markdownRefs));
159150

160151
return contextItems;
161152
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import {
2+
ContextItem,
3+
ContextProviderDescription,
4+
ContextProviderExtras,
5+
ContextSubmenuItem,
6+
IContextProvider,
7+
LoadSubmenuItemsArgs,
8+
} from "@continuedev/core";
9+
import * as fs from "fs";
10+
import * as os from "os";
11+
import * as path from "path";
12+
import * as vscode from "vscode";
13+
import Schemas from "../../database/schemas";
14+
import Table from "../../database/table";
15+
import {
16+
createContinueContextItems,
17+
findPossibleTables,
18+
refsToMarkdown,
19+
} from "../context";
20+
21+
const listDb2Table: ContextProviderDescription = {
22+
title: "list Db2i Tables",
23+
displayTitle: "Db2i-tables",
24+
description: "Add Db2i Table info to Context",
25+
type: "submenu",
26+
};
27+
28+
export let provider: ListDb2iTables = undefined;
29+
30+
class ListDb2iTables implements IContextProvider {
31+
constructor(private schema: string) {
32+
this.schema = schema;
33+
}
34+
35+
get description(): ContextProviderDescription {
36+
return listDb2Table;
37+
}
38+
39+
setCurrentSchema(schema: string) {
40+
this.schema = schema;
41+
}
42+
43+
getCurrentSchema() {
44+
return this.schema;
45+
}
46+
47+
async getColumnInfoForAllTables(schema: string) {
48+
const items: TableColumn[] = await Table.getItems(schema);
49+
50+
return items.map((column) => ({
51+
table_name: column.TABLE_NAME,
52+
schema: column.TABLE_SCHEMA,
53+
column_name: column.COLUMN_NAME,
54+
column_data_type: column.DATA_TYPE,
55+
}));
56+
}
57+
58+
async getContextItems(
59+
query: string,
60+
extras: ContextProviderExtras
61+
): Promise<ContextItem[]> {
62+
let contextItems: ContextItem[] = [];
63+
if (query.toUpperCase() === this.schema.toUpperCase()) {
64+
const tableInfo = await this.getColumnInfoForAllTables(this.schema);
65+
contextItems.push({
66+
name: `Info for all tables in ${this.schema}`,
67+
content: `Db2 for i table Assistant: The following table and column information is from the ${query} schema. Utilize the provided schema and table metadata to assist the user:\n${JSON.stringify(
68+
tableInfo
69+
)}`,
70+
description: "table metadata",
71+
});
72+
} else {
73+
const tableInfo = await findPossibleTables(
74+
null,
75+
this.schema,
76+
query.split(` `)
77+
);
78+
const markdownRefs = refsToMarkdown(tableInfo);
79+
80+
// add additional context for working with Db2 for i tables
81+
contextItems.push({
82+
name: `Instructions`,
83+
content: `Db2 for i table Assistant: The following information is based on the ${query} table within the ${this.schema} schema. Utilize the provided schema and table metadata to assist the user. Only use valid Db2 for i SQL syntax and conventions. If input is unclear ask user to clarify`,
84+
description: "instructions for working with Db2 for i tables",
85+
});
86+
87+
contextItems.push(...createContinueContextItems(markdownRefs));
88+
}
89+
return contextItems;
90+
}
91+
92+
async loadSubmenuItems(
93+
args: LoadSubmenuItemsArgs
94+
): Promise<ContextSubmenuItem[]> {
95+
const tables: BasicSQLObject[] = await Schemas.getObjects(this.schema, [
96+
`tables`,
97+
]);
98+
99+
const schemaSubmenuItem: ContextSubmenuItem = {
100+
id: this.schema,
101+
title: this.schema,
102+
description: `All table info in schema: ${this.schema}`,
103+
};
104+
105+
const tableSubmenuItems: ContextSubmenuItem[] = tables.map((table) => ({
106+
id: table.name,
107+
title: table.name,
108+
description: `${table.schema}-${table.name}`,
109+
}));
110+
111+
return [schemaSubmenuItem, ...tableSubmenuItems];
112+
}
113+
}
114+
115+
export async function registerDb2iTablesProvider(schema?: string) {
116+
if (!schema) {
117+
return;
118+
}
119+
const continueID = `Continue.continue`;
120+
const continueEx = vscode.extensions.getExtension(continueID);
121+
if (continueEx) {
122+
if (!continueEx.isActive) {
123+
await continueEx.activate();
124+
}
125+
126+
if (provider) {
127+
provider.setCurrentSchema(schema);
128+
// save continue config file to trigger a config reload to update list tables provider
129+
const configFile = path.join(os.homedir(), `.continue`, `config.json`);
130+
const now = new Date();
131+
fs.utimes(configFile, now, now, (err) => {
132+
if (err) {
133+
console.error("Error saving Continue config file:", err);
134+
return;
135+
}
136+
});
137+
} else {
138+
const continueAPI = continueEx?.exports;
139+
provider = new ListDb2iTables(schema);
140+
continueAPI?.registerCustomContextProvider(provider);
141+
}
142+
}
143+
}

src/database/table.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import { getInstance } from "../base";
55
export default class Table {
66
/**
77
* @param {string} schema Not user input
8-
* @param {string} name Not user input
8+
* @param {string} table Not user input
99
* @returns {Promise<TableColumn[]>}
1010
*/
11-
static async getItems(schema: string, name: string): Promise<TableColumn[]> {
11+
static async getItems(schema: string, table?: string): Promise<TableColumn[]> {
12+
const params = table ? [schema, table] : [schema];
1213
const sql = [
1314
`SELECT `,
1415
` column.TABLE_SCHEMA,`,
@@ -30,11 +31,14 @@ export default class Table {
3031
` column.table_schema = key.table_schema and`,
3132
` column.table_name = key.table_name and`,
3233
` column.column_name = key.column_name`,
33-
`WHERE column.TABLE_SCHEMA = ? AND column.TABLE_NAME = ?`,
34+
`WHERE column.TABLE_SCHEMA = ?`,
35+
...[
36+
table ? `AND column.TABLE_NAME = ?` : ``,
37+
],
3438
`ORDER BY column.ORDINAL_POSITION`,
3539
].join(` `);
3640

37-
return JobManager.runSQL(sql, {parameters: [schema, name]});
41+
return JobManager.runSQL(sql, {parameters: params});
3842
}
3943

4044
/**

src/extension.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import { JobManagerView } from "./views/jobManager/jobManagerView";
2323
import { SelfTreeDecorationProvider, selfCodesResultsView } from "./views/jobManager/selfCodes/selfCodesResultsView";
2424
import { registerContinueProvider } from "./aiProviders/continue/continueContextProvider";
2525
import { queryHistory } from "./views/queryHistoryView";
26-
import { activateChat, registerCopilotProvider } from "./aiProviders/copilot";
27-
import { SQLStatementChecker } from "./connection/syntaxChecker";
26+
import { registerCopilotProvider } from "./aiProviders/copilot";
27+
import { registerDb2iTablesProvider } from "./aiProviders/continue/listTablesContextProvider";
2828
import { setCheckerAvailableContext } from "./language/providers/problemProvider";
2929

3030
export interface Db2i {
@@ -101,6 +101,10 @@ export function activate(context: vscode.ExtensionContext): Db2i {
101101
onConnectOrServerInstall().then(() => {
102102
exampleBrowser.refresh();
103103
selfCodesView.setRefreshEnabled(Configuration.get(`jobSelfViewAutoRefresh`) || false);
104+
// register list tables
105+
const currentJob = JobManager.getSelection();
106+
const currentSchema = currentJob?.job.options.libraries[0];
107+
registerDb2iTablesProvider(currentSchema);
104108
if (devMode && runTests) {
105109
runTests();
106110
}
@@ -113,6 +117,8 @@ export function activate(context: vscode.ExtensionContext): Db2i {
113117
// register continue provider
114118
registerContinueProvider();
115119

120+
121+
116122
instance.subscribe(context, `disconnected`, `db2i-disconnected`, () => ServerComponent.reset());
117123

118124
return { sqlJobManager: JobManager, sqlJob: (options?: JDBCOptions) => new OldSQLJob(options) };

src/views/jobManager/jobManagerView.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { SelfCodesQuickPickItem } from "./selfCodes/selfCodesBrowser";
1212
import { updateStatusBar } from "./statusBar";
1313
import { setCancelButtonVisibility } from "../results";
1414
import { JDBCOptions } from "@ibm/mapepire-js/dist/src/types";
15+
import { provider, registerDb2iTablesProvider } from "../../aiProviders/continue/listTablesContextProvider";
1516
import { sqlLanguageStatus } from "../../language/providers";
1617

1718
const selectJobCommand = `vscode-db2i.jobManager.selectJob`;
@@ -303,10 +304,28 @@ export class JobManagerView implements TreeDataProvider<any> {
303304
updateStatusBar();
304305

305306
const selectedJob = JobManager.getSelection();
307+
308+
// re-register db2i tables context provider with current schema
309+
const selectedSchema = selectedJob?.job.options.libraries[0];
310+
const currentSchema = provider?.getCurrentSchema();
311+
if (
312+
provider &&
313+
selectedJob &&
314+
selectedSchema &&
315+
currentSchema.toLowerCase() !== selectedSchema.toLowerCase()
316+
) {
317+
registerDb2iTablesProvider(selectedSchema);
318+
}
306319

307-
setCancelButtonVisibility(selectedJob && selectedJob.job.getStatus() === "busy");
320+
setCancelButtonVisibility(
321+
selectedJob && selectedJob.job.getStatus() === "busy"
322+
);
308323
sqlLanguageStatus.setState(selectedJob !== undefined);
309-
commands.executeCommand(`setContext`, `vscode-db2i:jobManager.hasJob`, selectedJob !== undefined);
324+
commands.executeCommand(
325+
`setContext`,
326+
`vscode-db2i:jobManager.hasJob`,
327+
selectedJob !== undefined
328+
);
310329
}
311330

312331
getTreeItem(element: vscode.TreeItem) {

0 commit comments

Comments
 (0)