Skip to content

feat(add-comment): support reply_to_id for discussion threading from any trigger#24367

Merged
pelikhan merged 5 commits intomainfrom
copilot/add-comment-support-reply-to-id
Apr 3, 2026
Merged

feat(add-comment): support reply_to_id for discussion threading from any trigger#24367
pelikhan merged 5 commits intomainfrom
copilot/add-comment-support-reply-to-id

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

add-comment only auto-threaded discussion replies for discussion_comment-triggered workflows. Workflows triggered by workflow_dispatch (e.g. dispatched specialist agents) had no way to thread their reply under a specific comment, always producing top-level comments.

Changes

  • if (isDiscussion) block: replyToId now falls back to message.reply_to_id when the auto-thread path doesn't apply (not a bare discussion_comment trigger without explicit item_number). resolveTopLevelDiscussionCommentId is applied so nested reply node IDs are resolved to their top-level parent.

  • 404-fallback path: When an explicit item_number resolves to a Discussion (REST API → 404 → GraphQL retry), reply_to_id from the message is now honoured instead of hardcoding null. This is the primary path for workflow_dispatch-triggered workflows.

  • aw_context propagation: buildAwContext() and resolveItemContext() now include a comment_node_id field. For discussion / discussion_comment events, this captures payload.comment.node_id (the GraphQL node ID of the triggering comment). Dispatched specialist workflows receive this value in aw_context.comment_node_id and can pass it directly as reply_to_id in their add_comment output to thread replies under the triggering comment.

Usage

Agent output:

{
  "type": "add_comment",
  "item_number": 240,
  "body": "🔄 Updated finding...",
  "reply_to_id": "DC_kwDOParentComment456"
}

reply_to_id accepts both top-level and nested comment node IDs — nested IDs are automatically resolved to the top-level parent (GitHub Discussions supports only two nesting levels).

When the trigger is discussion_comment without an explicit item_number, the existing auto-thread behaviour takes precedence over any reply_to_id in the message.

End-to-end dispatch chain

  1. Feedback workflow (triggered by discussion_comment) dispatches a specialist via dispatch_workflowaw_context.comment_node_id carries the GraphQL node ID of the triggering comment.
  2. Specialist runs as workflow_dispatch, reads aw_context from its inputs, and sets reply_to_id to aw_context.comment_node_id in its add_comment output.
  3. add_comment threads the reply under the correct discussion comment.

When an agent outputs a reply_to_id field in the add_comment message,
the handler now uses it to post a threaded comment to a Discussion.
This works for both:
- discussion/discussion_comment events with explicit item_number
- workflow_dispatch events where item_number refers to a discussion
  (via the existing 404-fallback path to the GraphQL discussion API)

resolveTopLevelDiscussionCommentId is applied to reply_to_id to handle
the case where the caller passes a nested reply node ID rather than a
top-level comment node ID."

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/53f201fe-1abf-4a8a-9541-6de36a26c892

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for reply_to_id field in agent output feat(add-comment): support reply_to_id for discussion threading from any trigger Apr 3, 2026
Copilot AI requested a review from pelikhan April 3, 2026 20:31
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 3, 2026

@copilot make sure the aw_context message contains the reply_to_id information

Copilot AI and others added 2 commits April 3, 2026 21:10
Add comment_node_id (GraphQL node ID) to the aw_context object built
by buildAwContext() and resolveItemContext(). For discussion and
discussion_comment events, this captures payload.comment.node_id so
that dispatched specialist workflows receive the GraphQL node ID of the
triggering discussion comment via aw_context.comment_node_id.

The specialist can pass this value as reply_to_id in an add_comment
output to thread its reply under the triggering comment, completing
the CentralRepoOps dispatch chain end-to-end.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2ac8e162-7a35-4423-a934-4c4d4c91c3c2

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 3, 2026

@copilot make sure the aw_context message contains the reply_to_id information

Done in commit c4ef606. buildAwContext() now includes a comment_node_id field (the GraphQL node ID from payload.comment.node_id) for discussion / discussion_comment events. It's empty for all other event types (issues, PRs, checks) since reply_to_id threading is only applicable to GitHub Discussions.

The flow is:

  1. Feedback workflow (triggered by discussion_comment) dispatches the specialist — aw_context.comment_node_id carries the GraphQL node ID of the triggering comment.
  2. Specialist accesses ${{ inputs.aw_context }}, parses it, and sets reply_to_id in its add_comment output to thread the reply under the correct comment.

@pelikhan pelikhan marked this pull request as ready for review April 3, 2026 21:36
Copilot AI review requested due to automatic review settings April 3, 2026 21:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the add-comment safe output handler to support explicit discussion reply threading (reply_to_id) from non-discussion_comment triggers (notably workflow_dispatch), and propagates the triggering discussion comment’s GraphQL node ID through aw_context so dispatched workflows can reply in-thread.

Changes:

  • Update add_comment to honor message.reply_to_id for Discussions (including the REST→404→GraphQL fallback path) and resolve nested replies to top-level parents.
  • Extend aw_context to include comment_node_id (payload comment GraphQL node ID) for discussion/discussion_comment events.
  • Add/adjust unit tests to cover reply_to_id behavior and comment_node_id context propagation.
Show a summary per file
File Description
actions/setup/js/add_comment.cjs Uses reply_to_id to thread discussion replies outside the auto-threaded discussion_comment path; resolves nested reply IDs to top-level.
actions/setup/js/add_comment.test.cjs Adds tests for reply_to_id threading, top-level resolution, and precedence rules.
actions/setup/js/aw_context.cjs Adds comment_node_id to resolveItemContext() and buildAwContext() for discussion threading support in dispatched workflows.
actions/setup/js/aw_context.test.cjs Updates expectations and adds coverage for comment_node_id extraction.
actions/setup/js/generate_aw_info.test.cjs Adds coverage to ensure aw_context with comment_node_id is accepted and persisted.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 1

Comment on lines +593 to +601
let replyToId;
if (context.eventName === "discussion_comment" && !hasExplicitItemNumber) {
// When triggered by a discussion_comment event, thread the reply under the triggering comment.
replyToId = await resolveTopLevelDiscussionCommentId(githubClient, context.payload?.comment?.node_id);
} else if (message.reply_to_id) {
// Allow the agent to explicitly specify a reply_to_id (e.g. for workflow_dispatch-triggered
// workflows that know the target comment node ID). Apply resolveTopLevelDiscussionCommentId
// to handle cases where the caller passes a reply node ID instead of a top-level one.
replyToId = await resolveTopLevelDiscussionCommentId(githubClient, message.reply_to_id);
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

message.reply_to_id is passed directly into resolveTopLevelDiscussionCommentId() / GraphQL without type/format normalization. If an agent emits a non-string (number/object) or whitespace-only value, the subsequent node(id: $nodeId) query can fail and cause the handler to error. Consider coercing to String(...), trimming, and ignoring/ warning when the result is empty; ideally centralize this normalization so the same validated value is used for both the main discussion path and the 404 discussion fallback path.

Suggested change
let replyToId;
if (context.eventName === "discussion_comment" && !hasExplicitItemNumber) {
// When triggered by a discussion_comment event, thread the reply under the triggering comment.
replyToId = await resolveTopLevelDiscussionCommentId(githubClient, context.payload?.comment?.node_id);
} else if (message.reply_to_id) {
// Allow the agent to explicitly specify a reply_to_id (e.g. for workflow_dispatch-triggered
// workflows that know the target comment node ID). Apply resolveTopLevelDiscussionCommentId
// to handle cases where the caller passes a reply node ID instead of a top-level one.
replyToId = await resolveTopLevelDiscussionCommentId(githubClient, message.reply_to_id);
const normalizedExplicitReplyToId = message.reply_to_id === undefined || message.reply_to_id === null
? null
: String(message.reply_to_id).trim();
if (message.reply_to_id !== undefined && message.reply_to_id !== null && !normalizedExplicitReplyToId) {
core.warning("Ignoring empty discussion reply_to_id after normalization");
}
let replyToId;
if (context.eventName === "discussion_comment" && !hasExplicitItemNumber) {
// When triggered by a discussion_comment event, thread the reply under the triggering comment.
replyToId = await resolveTopLevelDiscussionCommentId(githubClient, context.payload?.comment?.node_id);
} else if (normalizedExplicitReplyToId) {
// Allow the agent to explicitly specify a reply_to_id (e.g. for workflow_dispatch-triggered
// workflows that know the target comment node ID). Apply resolveTopLevelDiscussionCommentId
// to handle cases where the caller passes a reply node ID instead of a top-level one.
replyToId = await resolveTopLevelDiscussionCommentId(githubClient, normalizedExplicitReplyToId);

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 3, 2026

@copilot

Review comments

Centralize normalization of message.reply_to_id: coerce to String,
trim whitespace, and warn+ignore when the result is empty. The
normalized value (normalizedExplicitReplyToId) is computed once before
the try/catch so both the main discussion path and the 404 discussion
fallback path share the same validated value.

Add two new tests: whitespace-only reply_to_id (warns and posts
top-level) and numeric reply_to_id (coerced to string "12345").

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/52b7c846-0f5e-4b30-9ce4-9358a3d5bc75

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 3, 2026

@copilot

Review comments

Applied in commit d08ee35. message.reply_to_id is now normalized once (coerced to String, trimmed) before the try/catch, so both the main discussion path and the 404 fallback use the same normalizedExplicitReplyToId. An empty result after normalization (e.g. whitespace-only) emits core.warning and is treated as no reply_to_id. Two new tests cover the whitespace-only and numeric coercion cases.

@pelikhan pelikhan merged commit 57b9a2b into main Apr 3, 2026
55 of 56 checks passed
@pelikhan pelikhan deleted the copilot/add-comment-support-reply-to-id branch April 3, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add-comment: support reply_to_id field in agent output for discussion threading

3 participants