Skip to content

Node: Add post user prompt hook#1774

Draft
SteveSandersonMS wants to merge 2 commits into
mainfrom
stevesa/onpostuserpromptsubmitted-hook
Draft

Node: Add post user prompt hook#1774
SteveSandersonMS wants to merge 2 commits into
mainfrom
stevesa/onpostuserpromptsubmitted-hook

Conversation

@SteveSandersonMS

@SteveSandersonMS SteveSandersonMS commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add Node SDK typed support for onPostUserPromptSubmitted
  • dispatch the runtime postUserPromptSubmitted hook through hooks.invoke
  • add a replayed Node E2E snapshot showing transformedPrompt mutation after runtime prompt transformation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review 🔍

This PR adds the postUserPromptSubmitted hook to the Node.js SDK. A quick scan of the other five SDK implementations shows this hook is not yet present in any of them.

SDKs that already have userPromptSubmitted but are missing postUserPromptSubmitted:

SDK userPromptSubmitted postUserPromptSubmitted
Node.js ✅ (this PR)
Python (python/copilot/session.py)
Go (go/types.go, go/session.go)
.NET (dotnet/src/Types.cs, dotnet/src/Session.cs)
Java (java/src/main/java/.../rpc/)
Rust (rust/src/hooks.rs)

Suggested additions per SDK (to match the Node.js contract):

  • Input fields: prompt (original) + transformedPrompt (runtime-enriched), plus the base fields (sessionId, timestamp, workingDirectory/cwd).
  • Output fields: modifiedTransformedPrompt? and suppressOutput?.
Rough equivalents for each SDK

Python (python/copilot/session.py)

class PostUserPromptSubmittedHookInput(TypedDict):
    sessionId: str
    timestamp: datetime
    workingDirectory: str
    prompt: str
    transformedPrompt: str

class PostUserPromptSubmittedHookOutput(TypedDict, total=False):
    modifiedTransformedPrompt: str
    suppressOutput: bool

PostUserPromptSubmittedHandler = Callable[
    [PostUserPromptSubmittedHookInput, dict[str, str]],
    PostUserPromptSubmittedHookOutput | None | Awaitable[...],
]

Wire into the hook dispatch map at "postUserPromptSubmitted" and add on_post_user_prompt_submitted to SessionHooks.

Go (go/types.go, go/session.go)

type PostUserPromptSubmittedHookInput struct {
    SessionID        string    `json:"sessionId"`
    Timestamp        time.Time `json:"-"`
    WorkingDirectory string    `json:"cwd"`
    Prompt           string    `json:"prompt"`
    TransformedPrompt string   `json:"transformedPrompt"`
}

type PostUserPromptSubmittedHookOutput struct {
    ModifiedTransformedPrompt string `json:"modifiedTransformedPrompt,omitempty"`
    SuppressOutput            bool   `json:"suppressOutput,omitempty"`
}

type PostUserPromptSubmittedHandler func(
    input PostUserPromptSubmittedHookInput,
    invocation HookInvocation,
) (*PostUserPromptSubmittedHookOutput, error)

Add OnPostUserPromptSubmitted PostUserPromptSubmittedHandler to SessionHooks and a case "postUserPromptSubmitted": in session.go.

.NET (dotnet/src/Types.cs, dotnet/src/Session.cs)

public sealed class PostUserPromptSubmittedHookInput
{
    [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty;
    [JsonPropertyName("timestamp")] public long Timestamp { get; set; }
    [JsonPropertyName("cwd")] public string WorkingDirectory { get; set; } = string.Empty;
    [JsonPropertyName("prompt")] public string Prompt { get; set; } = string.Empty;
    [JsonPropertyName("transformedPrompt")] public string TransformedPrompt { get; set; } = string.Empty;
}

public sealed class PostUserPromptSubmittedHookOutput
{
    [JsonPropertyName("modifiedTransformedPrompt")] public string? ModifiedTransformedPrompt { get; set; }
    [JsonPropertyName("suppressOutput")] public bool? SuppressOutput { get; set; }
}

Add OnPostUserPromptSubmitted property to SessionHooks and handle "postUserPromptSubmitted" in Session.cs.

Java (java/src/main/java/.../rpc/)

`@JsonIgnoreProperties`(ignoreUnknown = true)
public record PostUserPromptSubmittedHookInput(
    `@JsonProperty`("sessionId") String sessionId,
    `@JsonProperty`("timestamp") long timestamp,
    `@JsonProperty`("cwd") String cwd,
    `@JsonProperty`("prompt") String prompt,
    `@JsonProperty`("transformedPrompt") String transformedPrompt) {}

public record PostUserPromptSubmittedHookOutput(
    `@JsonProperty`("modifiedTransformedPrompt") String modifiedTransformedPrompt,
    `@JsonProperty`("suppressOutput") Boolean suppressOutput) {}

Add PostUserPromptSubmittedHandler interface, wire setOnPostUserPromptSubmitted into SessionHooks, and add a case "postUserPromptSubmitted": in CopilotSession.java.

Rust (rust/src/hooks.rs)

pub struct PostUserPromptSubmittedInput {
    pub session_id: String,
    pub timestamp: i64,
    #[serde(rename = "cwd")]
    pub working_directory: PathBuf,
    pub prompt: String,
    pub transformed_prompt: String,
}

pub struct PostUserPromptSubmittedOutput {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub modified_transformed_prompt: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub suppress_output: Option<bool>,
}

Add a PostUserPromptSubmitted variant to HookEvent/HookOutput, a default on_post_user_prompt_submitted method on the Hooks trait, and the matching parse/dispatch arms.

This is a suggestion for follow-up work rather than a blocker for this PR. The Node.js implementation establishes the contract cleanly; the other SDKs can follow the same pattern.

Generated by SDK Consistency Review Agent for issue #1774 · sonnet46 807.4K ·

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.

1 participant