Skip to content

Commit 375b4ea

Browse files
authored
Add issue-intent prompt suffix to issue mutation safe-output tools (#42776)
1 parent dfc4ad5 commit 375b4ea

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

actions/setup/js/generate_safe_outputs_tools.cjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525
* Default: ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json
2626
* GH_AW_SAFE_OUTPUTS_TOOLS_PATH - Output path for the generated tools.json
2727
* Default: ${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json
28+
* GH_AW_RUNTIME_FEATURES - Newline-delimited runtime features in key or key=value format
29+
* Parsed using runtime_features.cjs helpers
2830
*/
2931

3032
const fs = require("fs");
3133
const path = require("path");
3234
const { ERR_CONFIG } = require("./error_codes.cjs");
35+
const { parseRuntimeFeatures, hasRuntimeFeature } = require("./runtime_features.cjs");
3336

3437
const ADD_COMMENT_DEFAULT_DISCUSSIONS_NOTE =
3538
"NOTE: By default, this tool does not require discussions:write permission. Set 'discussions: true' in the workflow's safe-outputs.add-comment configuration to enable discussion comments and request this permission.";
@@ -117,6 +120,7 @@ async function main() {
117120
// This filters out non-tool config entries like dispatch_workflow, call_workflow,
118121
// mentions, max_bot_mentions, etc.
119122
const enabledToolNames = new Set(Object.keys(config).filter(k => sourceToolNames.has(k)));
123+
const runtimeFeatures = parseRuntimeFeatures(process.env.GH_AW_RUNTIME_FEATURES);
120124

121125
// Filter predefined tools to those enabled in config and apply enhancements
122126
const filteredTools = allTools
@@ -130,6 +134,9 @@ async function main() {
130134
if (descSuffix) {
131135
enhancedTool.description = (enhancedTool.description || "") + descSuffix;
132136
}
137+
if (hasRuntimeFeature(runtimeFeatures, "issue_intents") && ["set_issue_type", "set_issue_field", "add_labels"].includes(tool.name)) {
138+
enhancedTool.description = `${enhancedTool.description || ""} INTENT: Include rationale (max 280 chars) and confidence (LOW/MEDIUM/HIGH) with each call.`.trim();
139+
}
133140

134141
if (tool.name === "add_comment") {
135142
enhancedTool.description = updateAddCommentDescription(enhancedTool.description, config.add_comment);

actions/setup/js/generate_safe_outputs_tools.test.cjs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,48 @@ describe("generate_safe_outputs_tools", () => {
306306
expect(addCommentTool.description).toContain("Discussion comments are disabled for this workflow");
307307
expect(addCommentTool.description).not.toContain("Supports reply_to_id for discussion threading.");
308308
});
309+
310+
it("adds issue intent suffix for issue tools when issue_intents runtime feature is enabled", () => {
311+
fs.writeFileSync(
312+
toolsSourcePath,
313+
JSON.stringify([
314+
{ name: "set_issue_type", description: "Sets issue type.", inputSchema: { type: "object", properties: {} } },
315+
{ name: "set_issue_field", description: "Sets issue field.", inputSchema: { type: "object", properties: {} } },
316+
{ name: "add_labels", description: "Adds labels.", inputSchema: { type: "object", properties: {} } },
317+
{ name: "create_issue", description: "Creates a GitHub issue.", inputSchema: { type: "object", properties: {} } },
318+
])
319+
);
320+
fs.writeFileSync(configPath, JSON.stringify({ set_issue_type: {}, set_issue_field: {}, add_labels: {}, create_issue: {} }));
321+
fs.writeFileSync(toolsMetaPath, JSON.stringify({ description_suffixes: {}, repo_params: {}, dynamic_tools: [] }));
322+
323+
runScript({ GH_AW_RUNTIME_FEATURES: "other\nissue_intents\nanother=true" });
324+
325+
const result = JSON.parse(fs.readFileSync(outputPath, "utf8"));
326+
const intentSuffix = "INTENT: Include rationale (max 280 chars) and confidence (LOW/MEDIUM/HIGH) with each call.";
327+
expect(result.find((/** @type {{name: string, description: string}} */ t) => t.name === "set_issue_type").description).toContain(intentSuffix);
328+
expect(result.find((/** @type {{name: string, description: string}} */ t) => t.name === "set_issue_field").description).toContain(intentSuffix);
329+
expect(result.find((/** @type {{name: string, description: string}} */ t) => t.name === "add_labels").description).toContain(intentSuffix);
330+
expect(result.find((/** @type {{name: string, description: string}} */ t) => t.name === "create_issue").description).not.toContain(intentSuffix);
331+
});
332+
333+
it("does not add issue intent suffix when issue_intents runtime feature is not enabled", () => {
334+
fs.writeFileSync(
335+
toolsSourcePath,
336+
JSON.stringify([
337+
{ name: "set_issue_type", description: "Sets issue type.", inputSchema: { type: "object", properties: {} } },
338+
{ name: "set_issue_field", description: "Sets issue field.", inputSchema: { type: "object", properties: {} } },
339+
{ name: "add_labels", description: "Adds labels.", inputSchema: { type: "object", properties: {} } },
340+
])
341+
);
342+
fs.writeFileSync(configPath, JSON.stringify({ set_issue_type: {}, set_issue_field: {}, add_labels: {} }));
343+
fs.writeFileSync(toolsMetaPath, JSON.stringify({ description_suffixes: {}, repo_params: {}, dynamic_tools: [] }));
344+
345+
runScript({ GH_AW_RUNTIME_FEATURES: "other\nanother=true" });
346+
347+
const result = JSON.parse(fs.readFileSync(outputPath, "utf8"));
348+
const intentSuffix = "INTENT: Include rationale (max 280 chars) and confidence (LOW/MEDIUM/HIGH) with each call.";
349+
expect(result.find((/** @type {{name: string, description: string}} */ t) => t.name === "set_issue_type").description).not.toContain(intentSuffix);
350+
expect(result.find((/** @type {{name: string, description: string}} */ t) => t.name === "set_issue_field").description).not.toContain(intentSuffix);
351+
expect(result.find((/** @type {{name: string, description: string}} */ t) => t.name === "add_labels").description).not.toContain(intentSuffix);
352+
});
309353
});

0 commit comments

Comments
 (0)