Skip to content

Commit 1eae539

Browse files
committed
feat: add AI tool to fetch ECL Archive
1 parent f822bdb commit 1eae539

File tree

4 files changed

+127
-0
lines changed

4 files changed

+127
-0
lines changed

package.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,34 @@
244244
]
245245
}
246246
},
247+
{
248+
"name": "ecl-extension-getWorkunitECL",
249+
"tags": [
250+
"workunit",
251+
"ecl",
252+
"archive",
253+
"source",
254+
"code",
255+
"ecl-extension"
256+
],
257+
"toolReferenceName": "getWorkunitECL",
258+
"displayName": "Get Workunit ECL / ECL Archive",
259+
"modelDescription": "Retrieve the ECL archive (XML) for a specific workunit. Returns the original ECL code that was submitted to create the workunit. Requires a WUID (Workunit ID).",
260+
"canBeReferencedInPrompt": true,
261+
"icon": "$(code)",
262+
"inputSchema": {
263+
"type": "object",
264+
"properties": {
265+
"wuid": {
266+
"type": "string",
267+
"description": "The Workunit ID (WUID) to fetch ECL source for"
268+
}
269+
},
270+
"required": [
271+
"wuid"
272+
]
273+
}
274+
},
247275
{
248276
"name": "ecl-extension-syntaxCheck",
249277
"tags": [

src/ecl/lm/tools.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as vscode from "vscode";
22
import { FindWorkunitsTool } from "./tools/findWorkunits";
3+
import { GetWorkunitECLTool } from "./tools/getWorkunitECL";
34
import { FindLogicalFilesTool } from "./tools/findLogicalFiles";
45
import { SyntaxCheckTool } from "./tools/syntaxCheck";
56

@@ -9,6 +10,8 @@ export class ECLLMTools {
910

1011
protected constructor(ctx: vscode.ExtensionContext) {
1112
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-findWorkunits", new FindWorkunitsTool()));
13+
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-getWorkunitECL", new GetWorkunitECLTool()));
14+
1215
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-findLogicalFiles", new FindLogicalFilesTool()));
1316
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-syntaxCheck", new SyntaxCheckTool()));
1417
}

src/ecl/lm/tools/getWorkunitECL.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import * as vscode from "vscode";
2+
import { Workunit } from "@hpcc-js/comms";
3+
import { isPlatformConnected } from "../../../hpccplatform/session";
4+
import { reporter } from "../../../telemetry";
5+
import localize from "../../../util/localize";
6+
import { createServiceOptions, logToolEvent, requireConnectedSession, throwIfCancellationRequested } from "../utils";
7+
8+
export interface IGetWorkunitECLParameters {
9+
/**
10+
* Workunit ID (WUID) to fetch ECL source for
11+
*/
12+
wuid: string;
13+
}
14+
15+
export class GetWorkunitECLTool implements vscode.LanguageModelTool<IGetWorkunitECLParameters> {
16+
async invoke(options: vscode.LanguageModelToolInvocationOptions<IGetWorkunitECLParameters>, token: vscode.CancellationToken) {
17+
reporter?.sendTelemetryEvent("lmTool.invoke", { tool: "getWorkunitECL" });
18+
const params = options.input;
19+
20+
const wuid = typeof params.wuid === "string" ? params.wuid.trim() : "";
21+
if (wuid.length === 0) {
22+
throw new vscode.LanguageModelError(localize("WUID is required"), { cause: "invalid_parameters" });
23+
}
24+
25+
logToolEvent("getWorkunitECL", "invoke start", { wuid });
26+
27+
const session = requireConnectedSession();
28+
const opts = await createServiceOptions(session);
29+
30+
try {
31+
// Attach to the workunit and fetch its ECL source
32+
const wu = Workunit.attach(opts, wuid);
33+
await wu.refresh();
34+
35+
throwIfCancellationRequested(token);
36+
37+
const parts: vscode.LanguageModelTextPart[] = [];
38+
39+
// Add workunit basic information
40+
const detailsUrl = session.wuDetailsUrl(wu.Wuid);
41+
parts.push(new vscode.LanguageModelTextPart(localize("ECL Source for Workunit {0}:", wuid)));
42+
43+
const summary = localize(
44+
"Workunit {0} on {1} ({2})",
45+
wu.Wuid,
46+
wu.Cluster || localize("unknown cluster"),
47+
wu.State || localize("unknown state")
48+
);
49+
parts.push(new vscode.LanguageModelTextPart(summary));
50+
if (detailsUrl) {
51+
parts.push(new vscode.LanguageModelTextPart(`${localize("ECL Watch URL:")} ${detailsUrl}`));
52+
}
53+
54+
// Fetch ECL archive (XML format)
55+
throwIfCancellationRequested(token);
56+
const eclArchive = await wu.fetchArchive().catch(() => "");
57+
58+
if (eclArchive) {
59+
parts.push(new vscode.LanguageModelTextPart(localize("\nECL Archive (XML format):")));
60+
parts.push(new vscode.LanguageModelTextPart("```xml\n" + eclArchive + "\n```"));
61+
} else {
62+
parts.push(new vscode.LanguageModelTextPart(localize("No ECL archive available for this workunit.")));
63+
}
64+
65+
logToolEvent("getWorkunitECL", "invoke success", {
66+
wuid: wu.Wuid,
67+
state: wu.State,
68+
hasECL: !!eclArchive,
69+
});
70+
71+
return new vscode.LanguageModelToolResult(parts);
72+
} catch (error) {
73+
const errorMessage = error instanceof Error ? error.message : String(error);
74+
logToolEvent("getWorkunitECL", "invoke failed", { wuid, error: errorMessage });
75+
throw new vscode.LanguageModelError(
76+
localize("Failed to fetch workunit ECL: {0}", errorMessage),
77+
{ cause: error }
78+
);
79+
}
80+
}
81+
82+
async prepareInvocation(options: vscode.LanguageModelToolInvocationPrepareOptions<IGetWorkunitECLParameters>, _token: vscode.CancellationToken) {
83+
const connected = isPlatformConnected();
84+
const wuid = typeof options.input.wuid === "string" ? options.input.wuid.trim() : "";
85+
86+
return {
87+
invocationMessage: connected
88+
? localize("Fetching ECL source for workunit {0}", wuid || localize("(unspecified)"))
89+
: localize("Cannot fetch: HPCC Platform not connected"),
90+
confirmationMessages: connected ? undefined : {
91+
title: localize("HPCC Platform not connected"),
92+
message: new vscode.MarkdownString(localize("This tool requires an active HPCC connection.")),
93+
}
94+
};
95+
}
96+
}

test.tmp

Whitespace-only changes.

0 commit comments

Comments
 (0)