Skip to content

Commit 942122c

Browse files
authored
Add mssql_dab show flow and improve tool descripiton (#21511)
* Add DAB show flow and align tool contract * Stabilize DAB tool open and init behavior * Align DAB no-active-designer messaging * Improve DAB tool coverage * Fix DAB tool test coverage assertions
1 parent d32ffac commit 942122c

14 files changed

Lines changed: 634 additions & 311 deletions

File tree

extensions/mssql/l10n/bundle.l10n.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2673,6 +2673,14 @@
26732673
"{2} is the operation name 'apply_edits' and must not be translated"
26742674
]
26752675
},
2676+
"Data API Builder opened. Continue with {0} operations ({1}/{2})./{0} is the command identifier 'mssql_dab' and must not be translated{1} is the operation name 'get_state' and must not be translated{2} is the operation name 'apply_changes' and must not be translated": {
2677+
"message": "Data API Builder opened. Continue with {0} operations ({1}/{2}).",
2678+
"comment": [
2679+
"{0} is the command identifier 'mssql_dab' and must not be translated",
2680+
"{1} is the operation name 'get_state' and must not be translated",
2681+
"{2} is the operation name 'apply_changes' and must not be translated"
2682+
]
2683+
},
26762684
"Execute '{0}' operation on the schema designer?/{0} is the operation name": {
26772685
"message": "Execute '{0}' operation on the schema designer?",
26782686
"comment": ["{0} is the operation name"]
@@ -2690,6 +2698,8 @@
26902698
"message": "Executing '{0}' operation on Data API Builder",
26912699
"comment": ["{0} is the operation name"]
26922700
},
2701+
"No active schema designer found. Please open Data API Builder first using mssql_dab with operation 'show' or from the UI.": "No active schema designer found. Please open Data API Builder first using mssql_dab with operation 'show' or from the UI.",
2702+
"Missing connectionId. Please provide a connectionId to open Data API Builder.": "Missing connectionId. Please provide a connectionId to open Data API Builder.",
26932703
"No active schema designer found. Please open one first using mssql_schema_designer with operation 'show' or from the UI.": "No active schema designer found. Please open one first using mssql_schema_designer with operation 'show' or from the UI.",
26942704
"Schema designer state changed. Fetch the latest schema and retry the operation.": "Schema designer state changed. Fetch the latest schema and retry the operation.",
26952705
"Missing connectionId. Please provide a connectionId to open the schema designer.": "Missing connectionId. Please provide a connectionId to open the schema designer.",

extensions/mssql/package.json

Lines changed: 210 additions & 214 deletions
Large diffs are not rendered by default.

extensions/mssql/src/constants/locConstants.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,6 +2055,15 @@ export class MssqlChatAgent {
20552055
"{2} is the operation name 'apply_edits' and must not be translated",
20562056
],
20572057
});
2058+
public static dabToolShowSuccessMessage = l10n.t({
2059+
message: "Data API Builder opened. Continue with {0} operations ({1}/{2}).",
2060+
args: ["mssql_dab", "get_state", "apply_changes"],
2061+
comment: [
2062+
"{0} is the command identifier 'mssql_dab' and must not be translated",
2063+
"{1} is the operation name 'get_state' and must not be translated",
2064+
"{2} is the operation name 'apply_changes' and must not be translated",
2065+
],
2066+
});
20582067
public static schemaDesignerToolConfirmationTitle = l10n.t("Schema Designer");
20592068
public static schemaDesignerToolConfirmationMessage = (operation: string) => {
20602069
return l10n.t({
@@ -2085,6 +2094,12 @@ export class MssqlChatAgent {
20852094
comment: ["{0} is the operation name"],
20862095
});
20872096
};
2097+
public static dabToolNoActiveDesigner = l10n.t(
2098+
"No active schema designer found. Please open Data API Builder first using mssql_dab with operation 'show' or from the UI.",
2099+
);
2100+
public static dabToolMissingConnectionId = l10n.t(
2101+
"Missing connectionId. Please provide a connectionId to open Data API Builder.",
2102+
);
20882103
public static schemaDesignerNoActiveDesigner = l10n.t(
20892104
"No active schema designer found. Please open one first using mssql_schema_designer with operation 'show' or from the UI.",
20902105
);

extensions/mssql/src/controllers/mainController.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,14 @@ export default class MainController implements vscode.Disposable {
856856

857857
// Register mssql_dab tool
858858
this._context.subscriptions.push(
859-
vscode.lm.registerTool(Constants.copilotDabToolName, new DabTool()),
859+
vscode.lm.registerTool(
860+
Constants.copilotDabToolName,
861+
new DabTool(
862+
this.connectionManager,
863+
async (connectionUri: string, database: string) =>
864+
this.openDabDesigner(connectionUri, database),
865+
),
866+
),
860867
);
861868
}
862869

@@ -875,6 +882,21 @@ export default class MainController implements vscode.Disposable {
875882
return designer;
876883
}
877884

885+
private async openDabDesigner(connectionUri: string, database: string) {
886+
const designer = await SchemaDesignerWebviewManager.getInstance().getSchemaDesigner(
887+
this._context,
888+
this._vscodeWrapper,
889+
this,
890+
this.schemaDesignerService,
891+
database,
892+
undefined,
893+
connectionUri,
894+
);
895+
designer.showView(SchemaDesigner.SchemaDesignerActiveView.Dab);
896+
designer.revealToForeground();
897+
return designer;
898+
}
899+
878900
/**
879901
* Returns a flag indicating if the extension is initialized
880902
*/

extensions/mssql/src/copilot/prompts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const schemaDesignerAgentPrompt = `Use mssql_schema_designer for the acti
1010
Run get_overview, briefly summarize the schema, then ask what I want to explore or change.
1111
Do not apply edits until I confirm.`;
1212

13-
export const dabAgentPrompt = `Use mssql_dab for the active Data API Builder configuration.
13+
export const dabAgentPrompt = `Use mssql_dab for the Data API Builder configuration in the active schema designer.
1414
Run get_state, briefly summarize the current configuration, then ask what I want to review or change.
1515
Prefer mssql_dab for configuration tasks, and only use mssql_schema_designer if schema context is needed.
1616
Do not apply changes until I confirm.`;

extensions/mssql/src/copilot/tools/dabTool.ts

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as vscode from "vscode";
77
import { ToolBase } from "./toolBase";
88
import * as Constants from "../../constants/constants";
99
import { MssqlChatAgent as loc } from "../../constants/locConstants";
10+
import ConnectionManager from "../../controllers/connectionManager";
1011
import { SchemaDesignerWebviewManager } from "../../schemaDesigner/schemaDesignerWebviewManager";
1112
import { SchemaDesignerWebviewController } from "../../schemaDesigner/schemaDesignerWebviewController";
1213
import { SchemaDesigner } from "../../sharedInterfaces/schemaDesigner";
@@ -15,9 +16,10 @@ import { TelemetryActions, TelemetryViews } from "../../sharedInterfaces/telemet
1516
import { Dab } from "../../sharedInterfaces/dab";
1617
import { matchesStrictTargetHint, ToolTargetHint } from "./toolsUtils";
1718

18-
type DabToolOperation = "get_state" | "apply_changes";
19+
type DabToolOperation = "show" | "get_state" | "apply_changes";
1920

2021
export type DabToolParams =
22+
| { operation: "show"; connectionId: string }
2123
| { operation: "get_state" }
2224
| {
2325
operation: "apply_changes";
@@ -84,6 +86,16 @@ interface DabToolError {
8486
export class DabTool extends ToolBase<DabToolParams> {
8587
public readonly toolName = Constants.copilotDabToolName;
8688

89+
constructor(
90+
private _connectionManager: ConnectionManager,
91+
private _showDab: (
92+
connectionUri: string,
93+
database: string,
94+
) => Promise<SchemaDesignerWebviewController>,
95+
) {
96+
super();
97+
}
98+
8799
async call(
88100
options: vscode.LanguageModelToolInvocationOptions<DabToolParams>,
89101
_token: vscode.CancellationToken,
@@ -171,13 +183,57 @@ export class DabTool extends ToolBase<DabToolParams> {
171183
});
172184

173185
try {
186+
if (operation === "show") {
187+
const { connectionId } = options.input;
188+
if (!connectionId) {
189+
const err: DabToolError = {
190+
success: false,
191+
reason: "invalid_request",
192+
message: loc.dabToolMissingConnectionId,
193+
};
194+
sendToolTelemetry({ operation, success: false, reason: err.reason });
195+
return json(err);
196+
}
197+
198+
const connInfo = this._connectionManager.getConnectionInfo(connectionId);
199+
const connCreds = connInfo?.credentials;
200+
if (!connCreds) {
201+
const err: DabToolError = {
202+
success: false,
203+
reason: "invalid_request",
204+
message: loc.noConnectionError(connectionId),
205+
};
206+
sendToolTelemetry({ operation, success: false, reason: err.reason });
207+
return json(err);
208+
}
209+
210+
const designer = await this._showDab(connectionId, connCreds.database);
211+
sendToolTelemetry({
212+
operation,
213+
success: true,
214+
});
215+
216+
return json(
217+
withTarget(
218+
{
219+
success: true,
220+
message: loc.dabToolShowSuccessMessage,
221+
recommendedTool: this.toolName,
222+
recommendedNextCall: {
223+
operation: "get_state",
224+
},
225+
},
226+
designer,
227+
),
228+
);
229+
}
230+
174231
const activeDesigner = schemaDesignerManager.getActiveDesigner();
175232
if (!activeDesigner) {
176233
const err: DabToolError = {
177234
success: false,
178235
reason: "no_active_designer",
179-
message:
180-
"No active schema designer found. Please open a schema designer first.",
236+
message: loc.dabToolNoActiveDesigner,
181237
};
182238
sendToolTelemetry({ operation, success: false, reason: err.reason });
183239
return json(err);

extensions/mssql/src/reactviews/pages/SchemaDesigner/dab/dabContext.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ interface DabProviderProps {
4747

4848
export const DabProvider: React.FC<DabProviderProps> = ({ children }) => {
4949
const schemaDesignerContext = useContext(SchemaDesignerContext);
50-
const { extensionRpc, extractSchema, isInitialized } = schemaDesignerContext;
50+
const { extensionRpc, extractSchema, isInitialized, isInitializedRef, waitForInitialization } =
51+
schemaDesignerContext;
5152

5253
const [dabConfig, setDabConfig] = useState<Dab.DabConfig | null>(null);
5354
const [dabTextFilter, setDabTextFilter] = useState<string>("");
@@ -57,17 +58,12 @@ export const DabProvider: React.FC<DabProviderProps> = ({ children }) => {
5758
);
5859

5960
const dabConfigRef = useRef<Dab.DabConfig | null>(dabConfig);
60-
const isInitializedRef = useRef<boolean>(isInitialized);
6161
const extractSchemaRef = useRef<() => ReturnType<typeof extractSchema>>(extractSchema);
6262

6363
useEffect(() => {
6464
dabConfigRef.current = dabConfig;
6565
}, [dabConfig]);
6666

67-
useEffect(() => {
68-
isInitializedRef.current = isInitialized;
69-
}, [isInitialized]);
70-
7167
useEffect(() => {
7268
extractSchemaRef.current = extractSchema;
7369
}, [extractSchema]);
@@ -76,13 +72,14 @@ export const DabProvider: React.FC<DabProviderProps> = ({ children }) => {
7672
registerSchemaDesignerDabToolHandlers({
7773
extensionRpc,
7874
isInitializedRef,
75+
waitForInitialization,
7976
getCurrentDabConfig: () => dabConfigRef.current,
8077
getCurrentSchemaTables: () => extractSchemaRef.current().tables,
8178
commitDabConfig: (config) => {
8279
setDabConfig(config);
8380
},
8481
});
85-
}, [extensionRpc]);
82+
}, [extensionRpc, waitForInitialization]);
8683

8784
const initializeDabConfig = useCallback(() => {
8885
const schema = extractSchema();

extensions/mssql/src/reactviews/pages/SchemaDesigner/schemaDesignerRpcHandlers.ts

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,28 @@ function resolveEntityRef(
12661266
};
12671267
}
12681268

1269+
function createDabValidationError(message: string): {
1270+
success: false;
1271+
reason: DabApplyFailureReason;
1272+
message: string;
1273+
} {
1274+
return {
1275+
success: false,
1276+
reason: "validation_error",
1277+
message,
1278+
};
1279+
}
1280+
1281+
function createEntityWithEnabledActions(
1282+
entity: Dab.DabEntityConfig,
1283+
enabledActions: Dab.EntityAction[],
1284+
): Dab.DabEntityConfig {
1285+
return {
1286+
...entity,
1287+
enabledActions: [...enabledActions],
1288+
};
1289+
}
1290+
12691291
function applyDabToolChange(
12701292
config: Dab.DabConfig,
12711293
change: Dab.DabToolChange,
@@ -1319,33 +1341,21 @@ function applyDabToolChange(
13191341
return resolvedEntity;
13201342
}
13211343

1322-
if (!Array.isArray(change.actions) || change.actions.length === 0) {
1323-
return {
1324-
success: false,
1325-
reason: "validation_error",
1326-
message: "actions must be a non-empty array.",
1327-
};
1344+
if (!Array.isArray(change.enabledActions) || change.enabledActions.length === 0) {
1345+
return createDabValidationError("enabledActions must be a non-empty array.");
13281346
}
1329-
const uniqueActions = new Set(change.actions);
1330-
if (uniqueActions.size !== change.actions.length) {
1331-
return {
1332-
success: false,
1333-
reason: "validation_error",
1334-
message: "actions must be unique.",
1335-
};
1347+
const uniqueActions = new Set(change.enabledActions);
1348+
if (uniqueActions.size !== change.enabledActions.length) {
1349+
return createDabValidationError("enabledActions must be unique.");
13361350
}
1337-
if (change.actions.some((action) => !allowedActions.has(action))) {
1338-
return {
1339-
success: false,
1340-
reason: "validation_error",
1341-
message: "actions contains unsupported values.",
1342-
};
1351+
if (change.enabledActions.some((action) => !allowedActions.has(action))) {
1352+
return createDabValidationError("enabledActions contains unsupported values.");
13431353
}
13441354

1345-
config.entities[resolvedEntity.index] = {
1346-
...resolvedEntity.entity,
1347-
enabledActions: [...change.actions],
1348-
};
1355+
config.entities[resolvedEntity.index] = createEntityWithEnabledActions(
1356+
resolvedEntity.entity,
1357+
change.enabledActions,
1358+
);
13491359
return { success: true };
13501360
}
13511361

@@ -1509,21 +1519,26 @@ function applyDabToolChange(
15091519
export function registerSchemaDesignerDabToolHandlers(params: {
15101520
extensionRpc: WebviewRpc<SchemaDesigner.SchemaDesignerReducers>;
15111521
isInitializedRef: { current: boolean };
1522+
waitForInitialization: () => Promise<boolean>;
15121523
getCurrentDabConfig: () => Dab.DabConfig | null;
15131524
getCurrentSchemaTables: () => SchemaDesigner.Table[];
15141525
commitDabConfig: (config: Dab.DabConfig) => void;
15151526
}) {
15161527
const {
15171528
extensionRpc,
15181529
isInitializedRef,
1530+
waitForInitialization,
15191531
getCurrentDabConfig,
15201532
getCurrentSchemaTables,
15211533
commitDabConfig,
15221534
} = params;
15231535

15241536
const handleGetState = async (): Promise<Dab.GetDabToolStateResponse> => {
15251537
if (!isInitializedRef.current) {
1526-
throw new Error(locConstants.schemaDesigner.schemaDesignerNotInitialized);
1538+
const initialized = await waitForInitialization();
1539+
if (!initialized || !isInitializedRef.current) {
1540+
throw new Error(locConstants.schemaDesigner.schemaDesignerNotInitialized);
1541+
}
15271542
}
15281543

15291544
const baseSnapshot = getCurrentDabConfig();

extensions/mssql/src/reactviews/pages/SchemaDesigner/schemaDesignerStateProvider.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { stateStack } from "./schemaDesignerUndoState";
3030

3131
export interface SchemaDesignerContextProps extends CoreRPCs {
3232
extensionRpc: WebviewRpc<SchemaDesigner.SchemaDesignerReducers>;
33+
isInitializedRef: { current: boolean };
34+
waitForInitialization: () => Promise<boolean>;
3335
schemaNames: string[];
3436
datatypes: string[];
3537
findTableText: string;
@@ -535,6 +537,8 @@ const SchemaDesignerStateProvider: React.FC<SchemaDesignerProviderProps> = ({ ch
535537
value={{
536538
...getCoreRPCs(extensionRpc),
537539
extensionRpc,
540+
isInitializedRef,
541+
waitForInitialization,
538542
schemaNames,
539543
datatypes,
540544
findTableText,

extensions/mssql/src/sharedInterfaces/dab.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ export namespace Dab {
229229
export type DabToolChange =
230230
| { type: "set_api_types"; apiTypes: ApiType[] }
231231
| { type: "set_entity_enabled"; entity: DabEntityRef; isEnabled: boolean }
232-
| { type: "set_entity_actions"; entity: DabEntityRef; actions: EntityAction[] }
232+
| { type: "set_entity_actions"; entity: DabEntityRef; enabledActions: EntityAction[] }
233233
| { type: "patch_entity_settings"; entity: DabEntityRef; set: DabEntitySettingsPatch }
234234
| { type: "set_only_enabled_entities"; entities: DabEntityRef[] }
235235
| { type: "set_all_entities_enabled"; isEnabled: boolean };

0 commit comments

Comments
 (0)