Skip to content

Commit 27702f9

Browse files
Merge branch 'main' into copilot/aw-fix-blog-auditor-tool
2 parents 6a999d3 + 13d4bd7 commit 27702f9

18 files changed

Lines changed: 512 additions & 47 deletions

.github/workflows/daily-go-test-parallelizer.lock.yml

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/daily-go-test-parallelizer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ permissions:
1313
engine:
1414
id: codex
1515
model-provider: openai
16-
model: openai/gpt-5.4
16+
model: openai/gpt-5.3-codex
1717
strict: true
1818
timeout-minutes: 30
1919
network:

actions/setup/js/safe_output_handler_manager.cjs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,21 @@ async function processMessages(messageHandlers, messages, onItemCreated = null)
11661166
// Check if this output was created with unresolved temporary IDs
11671167
// For create_issue, create_discussion, add_comment - check if body has unresolved IDs
11681168

1169-
// Handle add_comment which returns an array of comments
1169+
// Handle the current add_comment result shape.
1170+
if (messageType === "add_comment" && result?.commentId && result?.repo) {
1171+
const contentToCheck = getContentToCheck(messageType, message, result);
1172+
if (contentToCheck && hasUnresolvedTemporaryIds(contentToCheck, temporaryIdMap, artifactUrlMap)) {
1173+
core.info(`Comment ${result.commentId} on ${result.repo}#${result.itemNumber} was created with unresolved temporary IDs - tracking for update`);
1174+
outputsWithUnresolvedIds.push({
1175+
type: messageType,
1176+
message,
1177+
result,
1178+
originalTempIdMapSize: tempIdMapSizeBefore,
1179+
});
1180+
}
1181+
}
1182+
1183+
// Handle the legacy add_comment result shape.
11701184
if (messageType === "add_comment" && Array.isArray(result)) {
11711185
const contentToCheck = getContentToCheck(messageType, message, result);
11721186
if (contentToCheck && hasUnresolvedTemporaryIds(contentToCheck, temporaryIdMap, artifactUrlMap)) {
@@ -1177,12 +1191,7 @@ async function processMessages(messageHandlers, messages, onItemCreated = null)
11771191
outputsWithUnresolvedIds.push({
11781192
type: messageType,
11791193
message: message,
1180-
result: {
1181-
commentId: comment._tracking.commentId,
1182-
itemNumber: comment._tracking.itemNumber,
1183-
repo: comment._tracking.repo,
1184-
isDiscussion: comment._tracking.isDiscussion,
1185-
},
1194+
result: { ...comment._tracking, ...(comment.body ? { body: comment.body } : {}) },
11861195
originalTempIdMapSize: tempIdMapSizeBefore,
11871196
});
11881197
}
@@ -1384,7 +1393,7 @@ function getContentToCheck(messageType, message, result) {
13841393
case "create_discussion":
13851394
return message.body || "";
13861395
case "add_comment":
1387-
return message.body || "";
1396+
return result?.body || message.body || "";
13881397
case "comment_memory":
13891398
return result?.managedBody || message.body || "";
13901399
case "create_pull_request":
@@ -2026,4 +2035,5 @@ module.exports = {
20262035
partitionFailureResults,
20272036
computeSafeOutputsStatus,
20282037
setSafeOutputsStatusOutputs,
2038+
processSyntheticUpdates,
20292039
};

actions/setup/js/safe_output_handler_manager.test.cjs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
partitionFailureResults,
2222
computeSafeOutputsStatus,
2323
setSafeOutputsStatusOutputs,
24+
processSyntheticUpdates,
2425
} from "./safe_output_handler_manager.cjs";
2526

2627
const require = createRequire(import.meta.url);
@@ -153,6 +154,88 @@ describe("Safe Output Handler Manager", () => {
153154

154155
expect(sortMessageIndicesByTemporaryIdDependencies([dependent, producer, unrelated])).toEqual([1, 0, 2]);
155156
});
157+
158+
it("tracks a comment emitted before its temporary-ID producer", async () => {
159+
const callOrder = [];
160+
const handlers = new Map([
161+
[
162+
"add_comment",
163+
vi.fn(async (_message, resolvedTemporaryIds) => {
164+
callOrder.push("add_comment");
165+
expect(resolvedTemporaryIds).toEqual({});
166+
return {
167+
success: true,
168+
commentId: 123,
169+
itemNumber: 42,
170+
repo: "owner/repo",
171+
isDiscussion: false,
172+
body: "Tracking issue: #aw_track1\n\nHandler footer marker",
173+
};
174+
}),
175+
],
176+
[
177+
"create_issue",
178+
vi.fn(async () => {
179+
callOrder.push("create_issue");
180+
return { success: true, temporaryId: "aw_track1", repo: "owner/tracker", number: 99 };
181+
}),
182+
],
183+
]);
184+
const messages = [
185+
{ type: "add_comment", item_number: 42, body: "Tracking issue: #aw_track1" },
186+
{ type: "create_issue", temporary_id: "aw_track1", title: "Tracking issue" },
187+
];
188+
189+
const result = await processMessages(handlers, messages);
190+
191+
expect(callOrder).toEqual(["add_comment", "create_issue"]);
192+
expect(result.temporaryIdMap.aw_track1).toEqual({ repo: "owner/tracker", number: 99 });
193+
expect(result.outputsWithUnresolvedIds).toEqual([
194+
{
195+
type: "add_comment",
196+
message: { type: "add_comment", item_number: 42, body: "Tracking issue: #aw_track1" },
197+
result: {
198+
success: true,
199+
commentId: 123,
200+
itemNumber: 42,
201+
repo: "owner/repo",
202+
isDiscussion: false,
203+
body: "Tracking issue: #aw_track1\n\nHandler footer marker",
204+
},
205+
originalTempIdMapSize: 0,
206+
},
207+
]);
208+
});
209+
210+
it("updates the posted comment body while retaining handler metadata", async () => {
211+
const updateComment = vi.fn().mockResolvedValue({});
212+
const github = { rest: { issues: { updateComment } } };
213+
const trackedOutputs = [
214+
{
215+
type: "add_comment",
216+
message: { type: "add_comment", body: "Tracking issue: #aw_track1" },
217+
result: {
218+
success: true,
219+
commentId: 123,
220+
itemNumber: 42,
221+
repo: "owner/repo",
222+
isDiscussion: false,
223+
body: "Tracking issue: #aw_track1\n\nHandler footer marker",
224+
},
225+
originalTempIdMapSize: 0,
226+
},
227+
];
228+
229+
const updateCount = await processSyntheticUpdates(github, {}, trackedOutputs, new Map([["aw_track1", { repo: "owner/tracker", number: 99 }]]), new Map());
230+
231+
expect(updateCount).toBe(1);
232+
expect(updateComment).toHaveBeenCalledWith({
233+
owner: "owner",
234+
repo: "repo",
235+
comment_id: 123,
236+
body: "Tracking issue: owner/tracker#99\n\nHandler footer marker",
237+
});
238+
});
156239
});
157240

158241
describe("logCreatedItemFromResult", () => {

cmd/gh-aw/compile_flags_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,20 @@ func TestCompileOptionsPropagateForceRefreshContainerPins(t *testing.T) {
4646
t.Fatal("expected ForceRefreshContainerPins to be propagated to CompileConfig")
4747
}
4848
}
49+
50+
func TestCompileOptionsPropagateModels(t *testing.T) {
51+
t.Parallel()
52+
53+
modelsFlag := compileCmd.Flags().Lookup("models")
54+
if modelsFlag == nil {
55+
t.Fatal("expected --models flag on compile command")
56+
}
57+
if modelsFlag.DefValue != "false" {
58+
t.Fatalf("expected --models default to be false, got %s", modelsFlag.DefValue)
59+
}
60+
61+
config := (&compileCmdOptions{models: true}).toCompileConfig(nil)
62+
if !config.Models {
63+
t.Fatal("expected Models to be propagated to CompileConfig")
64+
}
65+
}

cmd/gh-aw/main.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ type compileCmdOptions struct {
428428
showAllErrors bool
429429
fix bool
430430
stats bool
431+
models bool
431432
failFast bool
432433
noCheckUpdate bool
433434
staged bool
@@ -472,6 +473,7 @@ func getCompileCmdOptions(cmd *cobra.Command) compileCmdOptions {
472473
showAllErrors, _ := cmd.Flags().GetBool("show-all")
473474
fix, _ := cmd.Flags().GetBool("fix")
474475
stats, _ := cmd.Flags().GetBool("stats")
476+
models, _ := cmd.Flags().GetBool("models")
475477
failFast, _ := cmd.Flags().GetBool("fail-fast")
476478
noCheckUpdate, _ := cmd.Flags().GetBool("no-check-update")
477479
scheduleSeed, _ := cmd.Flags().GetString("schedule-seed")
@@ -488,7 +490,7 @@ func getCompileCmdOptions(cmd *cobra.Command) compileCmdOptions {
488490
validate: validate, watch: watch, noEmit: noEmit, purge: purge, strict: strict, trial: trial, dependabot: dependabot,
489491
forceOverwrite: forceOverwrite, refreshStopTime: refreshStopTime, forceRefreshActionPins: forceRefreshActionPins, forceRefreshContainerPins: forceRefreshContainerPins, allowActionRefs: allowActionRefs,
490492
zizmor: zizmor, poutine: poutine, actionlint: actionlint, runnerGuard: runnerGuard, syft: syft, grype: grype, grant: grant, yamllint: yamllint, shellcheck: shellcheck,
491-
jsonOutput: jsonOutput, showAllErrors: showAllErrors, fix: fix, stats: stats, failFast: failFast, noCheckUpdate: noCheckUpdate,
493+
jsonOutput: jsonOutput, showAllErrors: showAllErrors, fix: fix, stats: stats, models: models, failFast: failFast, noCheckUpdate: noCheckUpdate,
492494
staged: staged, approve: approve, validateImages: validateImages, ghes: ghes, verbose: verbose, useSamples: useSamples,
493495
}
494496
}
@@ -521,7 +523,7 @@ func (o *compileCmdOptions) toCompileConfig(args []string) cli.CompileConfig {
521523
Dependabot: o.dependabot, ForceOverwrite: o.forceOverwrite, RefreshStopTime: o.refreshStopTime, ForceRefreshActionPins: o.forceRefreshActionPins, ForceRefreshContainerPins: o.forceRefreshContainerPins,
522524
AllowActionRefs: o.allowActionRefs, Zizmor: o.zizmor, Poutine: o.poutine, Actionlint: o.actionlint, RunnerGuard: o.runnerGuard,
523525
Syft: o.syft, Grype: o.grype, Grant: o.grant, Yamllint: o.yamllint, Shellcheck: o.shellcheck, JSONOutput: o.jsonOutput, ShowAllErrors: o.showAllErrors,
524-
Stats: o.stats, FailFast: o.failFast, ScheduleSeed: o.scheduleSeed, Staged: o.staged, Approve: o.approve,
526+
Stats: o.stats, Models: o.models, FailFast: o.failFast, ScheduleSeed: o.scheduleSeed, Staged: o.staged, Approve: o.approve,
525527
ValidateImages: o.validateImages, PriorManifestFile: o.priorManifestFile, GHESCompat: o.ghes, UseSamples: o.useSamples,
526528
}
527529
}
@@ -546,7 +548,9 @@ func runCompileCmd(cmd *cobra.Command, args []string) error {
546548
return err
547549
}
548550
}
549-
if _, err := cli.CompileWorkflows(cmd.Context(), opts.toCompileConfig(args)); err != nil {
551+
config := opts.toCompileConfig(args)
552+
cli.PrepareCompileModelValidation(cmd.Context(), &config)
553+
if _, err := cli.CompileWorkflows(cmd.Context(), config); err != nil {
550554
return err
551555
}
552556
return nil
@@ -793,6 +797,7 @@ func configureCompileToolFlags() {
793797
compileCmd.Flags().BoolP("json", "j", false, "Output results in JSON format")
794798
compileCmd.Flags().Bool("show-all", false, "Display all compilation errors instead of only the highest-priority subset (default: top 5)")
795799
compileCmd.Flags().Bool("stats", false, "Display statistics table sorted by workflow file size (shows jobs, steps, scripts, and shells)")
800+
compileCmd.Flags().Bool("models", false, "Warn when models configured in models or engine.models are absent from the active model inventory")
796801
compileCmd.Flags().Bool("fail-fast", false, "Stop at the first validation error instead of collecting all errors")
797802
compileCmd.Flags().Bool("no-check-update", false, "Skip checking for gh-aw updates")
798803
compileCmd.Flags().String("schedule-seed", "", "Override the repository slug (owner/repo) used as seed for fuzzy schedule scattering (e.g., \"github/gh-aw\"). Bypasses git remote detection entirely. Use this when your git remote is not named \"origin\" and you have multiple remotes configured")

0 commit comments

Comments
 (0)