Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,34 @@
]
}
},
{
"name": "ecl-extension-getWorkunitECL",
"tags": [
"workunit",
"ecl",
"archive",
"source",
"code",
"ecl-extension"
],
"toolReferenceName": "getWorkunitECL",
"displayName": "Get Workunit ECL / ECL Archive",
"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).",
"canBeReferencedInPrompt": true,
"icon": "$(code)",
"inputSchema": {
"type": "object",
"properties": {
"wuid": {
"type": "string",
"description": "The Workunit ID (WUID) to fetch ECL source for"
}
},
"required": [
"wuid"
]
}
},
{
"name": "ecl-extension-syntaxCheck",
"tags": [
Expand Down
2 changes: 2 additions & 0 deletions src/ecl/lm/tools.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from "vscode";
import { FindWorkunitsTool } from "./tools/findWorkunits";
import { GetWorkunitErrorsTool } from "./tools/getWorkunitErrors";
import { GetWorkunitECLTool } from "./tools/getWorkunitECL";
import { FindLogicalFilesTool } from "./tools/findLogicalFiles";
import { SyntaxCheckTool } from "./tools/syntaxCheck";

Expand All @@ -11,6 +12,7 @@ export class ECLLMTools {
protected constructor(ctx: vscode.ExtensionContext) {
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-findWorkunits", new FindWorkunitsTool()));
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-getWorkunitErrors", new GetWorkunitErrorsTool()));
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-getWorkunitECL", new GetWorkunitECLTool()));

ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-findLogicalFiles", new FindLogicalFilesTool()));
ctx.subscriptions.push(vscode.lm.registerTool("ecl-extension-syntaxCheck", new SyntaxCheckTool()));
Expand Down
90 changes: 90 additions & 0 deletions src/ecl/lm/tools/getWorkunitECL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import * as vscode from "vscode";
import { Workunit } from "@hpcc-js/comms";
import { isPlatformConnected } from "../../../hpccplatform/session";
import { reporter } from "../../../telemetry";
import localize from "../../../util/localize";
import { createServiceOptions, logToolEvent, requireConnectedSession, throwIfCancellationRequested } from "../utils/index";

export interface IGetWorkunitECLParameters {
wuid: string;
}

export class GetWorkunitECLTool implements vscode.LanguageModelTool<IGetWorkunitECLParameters> {
async invoke(options: vscode.LanguageModelToolInvocationOptions<IGetWorkunitECLParameters>, token: vscode.CancellationToken) {
reporter?.sendTelemetryEvent("lmTool.invoke", { tool: "getWorkunitECL" });
const params = options.input;

const wuid = typeof params.wuid === "string" ? params.wuid.trim() : "";
if (wuid.length === 0) {
throw new vscode.LanguageModelError(localize("WUID is required"), { cause: "invalid_parameters" });
}

logToolEvent("getWorkunitECL", "invoke start", { wuid });

const session = requireConnectedSession();
const opts = await createServiceOptions(session);

try {
const wu = Workunit.attach(opts, wuid);
await wu.refresh();

throwIfCancellationRequested(token);

const parts: vscode.LanguageModelTextPart[] = [];

const detailsUrl = session.wuDetailsUrl(wu.Wuid);
parts.push(new vscode.LanguageModelTextPart(localize("ECL Source for Workunit {0}:", wuid)));

const summary = localize(
"Workunit {0} on {1} ({2})",
wu.Wuid,
wu.Cluster || localize("unknown cluster"),
wu.State || localize("unknown state")
);
parts.push(new vscode.LanguageModelTextPart(summary));
if (detailsUrl) {
parts.push(new vscode.LanguageModelTextPart(`${localize("ECL Watch URL:")} ${detailsUrl}`));
}

throwIfCancellationRequested(token);
const eclArchive = await wu.fetchArchive().catch(() => "");

if (eclArchive) {
parts.push(new vscode.LanguageModelTextPart(localize("\nECL Archive (XML format):")));
parts.push(new vscode.LanguageModelTextPart("```xml\n" + eclArchive + "\n```"));
} else {
parts.push(new vscode.LanguageModelTextPart(localize("No ECL archive available for this workunit.")));
}

logToolEvent("getWorkunitECL", "invoke success", {
wuid: wu.Wuid,
state: wu.State,
hasECL: !!eclArchive,
});

return new vscode.LanguageModelToolResult(parts);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logToolEvent("getWorkunitECL", "invoke failed", { wuid, error: errorMessage });
throw new vscode.LanguageModelError(
localize("Failed to fetch workunit ECL: {0}", errorMessage),
{ cause: error }
);
}
}

async prepareInvocation(options: vscode.LanguageModelToolInvocationPrepareOptions<IGetWorkunitECLParameters>, _token: vscode.CancellationToken) {
const connected = isPlatformConnected();
const wuid = typeof options.input.wuid === "string" ? options.input.wuid.trim() : "";

return {
invocationMessage: connected
? localize("Fetching ECL source for workunit {0}", wuid || localize("(unspecified)"))
: localize("Cannot fetch: HPCC Platform not connected"),
confirmationMessages: connected ? undefined : {
title: localize("HPCC Platform not connected"),
message: new vscode.MarkdownString(localize("This tool requires an active HPCC connection.")),
}
};
}
}
6 changes: 0 additions & 6 deletions src/ecl/lm/tools/getWorkunitErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ interface FormattedException {
}

export interface IGetWorkunitErrorsParameters {
/**
* Workunit ID (WUID) to fetch errors and warnings for
*/
wuid: string;
}

Expand Down Expand Up @@ -86,15 +83,13 @@ export class GetWorkunitErrorsTool implements vscode.LanguageModelTool<IGetWorku
const opts = await createServiceOptions(session);

try {
// Attach to the workunit and fetch its details
const wu = Workunit.attach(opts, wuid);
await wu.refresh();

throwIfCancellationRequested(token);

const parts: vscode.LanguageModelTextPart[] = [];

// Add workunit basic state information
const detailsUrl = session.wuDetailsUrl(wu.Wuid);
parts.push(new vscode.LanguageModelTextPart(localize("Errors/Warnings for Workunit {0}:", wuid)));

Expand All @@ -106,7 +101,6 @@ export class GetWorkunitErrorsTool implements vscode.LanguageModelTool<IGetWorku
);
parts.push(new vscode.LanguageModelTextPart(summary));

// Fetch and add exceptions (errors and warnings)
const exceptions = await wu.fetchECLExceptions().catch(() => []);
throwIfCancellationRequested(token);

Expand Down